Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04d9a4e12d |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,29 +1,15 @@
|
|||||||
# ESP-IDF default build directory
|
# ESP-IDF default build directory
|
||||||
build
|
build
|
||||||
sdkconfig.old
|
|
||||||
dependencies.lock
|
|
||||||
|
|
||||||
# VIM files
|
# VIM files
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
**/.cache
|
|
||||||
|
|
||||||
# VS-code
|
|
||||||
settings.json
|
|
||||||
|
|
||||||
# drawio files
|
# drawio files
|
||||||
*.bkp
|
*.bkp
|
||||||
|
|
||||||
# freecad backup files
|
# freecad backup files
|
||||||
*.FCStd1
|
*.FCStd1
|
||||||
*.FCBak
|
|
||||||
# stl files are usually temporary
|
|
||||||
*.stl
|
|
||||||
|
|
||||||
# kicad backup files
|
# kicad backup files
|
||||||
pcb/*/*backups/
|
pcb/*/*backups/
|
||||||
|
|
||||||
# other
|
|
||||||
octave-workspace
|
|
||||||
del
|
|
||||||
screenshots
|
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ cmake_minimum_required(VERSION 3.5)
|
|||||||
|
|
||||||
#set(EXTRA_COMPONENT_DIRS ../esp-idf-lib/components)
|
#set(EXTRA_COMPONENT_DIRS ../esp-idf-lib/components)
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(cable-length-cutter)
|
project(cable-length-cutting)
|
||||||
|
|||||||
104
README.md
104
README.md
@@ -1,94 +1,18 @@
|
|||||||
# Overview
|
# Hardware
|
||||||
Firmware and documentation of a custom built machine that winds and cuts cable to certain lengths.
|
## connection plan
|
||||||
Extensive details about this project can be found on the website: [pfusch.zone/cable-length-cutter](https://pfusch.zone/cable-length-cutter)
|
See [connection-plan.pdf](connection-plan.pdf)
|
||||||
|
|
||||||
<img src="img/cable-length-cutter.jpg" alt="Photo machine" style="width:60%;">
|
|
||||||
|
|
||||||
Photo of the built machine
|
|
||||||
|
|
||||||
## Current Features
|
|
||||||
- Measure length using rotary encoder
|
|
||||||
- Wind to set length while start-button is pressed
|
|
||||||
- Automatic wire cutter
|
|
||||||
- Control interface:
|
|
||||||
- 2x 7-Segment display showing lengths and notifications
|
|
||||||
- Buzzer for acoustic notifications
|
|
||||||
- 4 Buttons and Potentiometer for setting the target length
|
|
||||||
- Reset and Cut Button
|
|
||||||
- Stepper motor controlling a linear axis guiding the cable while winding
|
|
||||||
- Store last axis position at shutdown
|
|
||||||
|
|
||||||
|
|
||||||
# Usage
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
# Electrical Details
|
|
||||||
For detailed documentation of all electrical aspects, see [connection-plan.pdf](connection-plan.pdf).
|
|
||||||
|
|
||||||
|
|
||||||
# Printed Parts
|
|
||||||
All designed and 3D-printed parts can be found in the [cad/](cad/) folder. These parts were designed using FreeCAD.
|
|
||||||
|
|
||||||
|
|
||||||
# Components
|
# Components
|
||||||
### Custom pcb with ESP-32 microcontroller
|
## rotary encoder LPD3806-600BM-G5-24C
|
||||||
See [connection-plan.pdf](connection-plan.pdf)
|
- Pulses: 600 p/r (Single-phase 600 pulses /R,Two phase 4 frequency doubling to 2400 pulses)
|
||||||
|
- Power source: DC5-24V
|
||||||
|
- Shaft: 6*13mm/0.23*0.51"
|
||||||
|
- Size: 38*35.5mm/1.49*1.39"
|
||||||
|
- Output :AB 2phase output rectangular orthogonal pulse circuit, the output for the NPN open collector output type
|
||||||
|
- Maximum mechanical speed: 5000 R / min
|
||||||
|
- Response frequency: 0-20KHz
|
||||||
|
- Cable length: 1.5 meter
|
||||||
|
- size: http://domoticx.com/wp-content/uploads/2020/05/LPD3806-afmetingen.jpg
|
||||||
|
- Wires: Green = A phase, white = B phase, red = Vcc power +, black = V0
|
||||||
|
|
||||||
### Rotary encoder LPD3806-600BM-G5-24C
|
|
||||||
```
|
|
||||||
- Pulses: 600 p/r (Single-phase 600 pulses /R,Two phase 4 frequency doubling to 2400 pulses)
|
|
||||||
- Power source: DC5-24V
|
|
||||||
- Shaft: 6*13mm/0.23*0.51"
|
|
||||||
- Size: 38*35.5mm/1.49*1.39"
|
|
||||||
- Output :AB 2phase output rectangular orthogonal pulse circuit, the output for the NPN open collector output type
|
|
||||||
- Maximum mechanical speed: 5000 R / min
|
|
||||||
- Response frequency: 0-20KHz
|
|
||||||
- Cable length: 1.5 meter
|
|
||||||
- size: http://domoticx.com/wp-content/uploads/2020/05/LPD3806-afmetingen.jpg
|
|
||||||
- Wires: Green = A phase, white = B phase, red = Vcc power +, black = V0
|
|
||||||
```
|
|
||||||
### Variable Frequency Drive T13-400W-12-H
|
|
||||||
See [docs/vfd/](docs/vfd/)
|
|
||||||
|
|
||||||
### Stepper-driver TB6600
|
|
||||||
See [docs/stepper-driver_TB6600-Manual.pdf](docs/stepper-driver_TB6600-Manual.pdf)
|
|
||||||
|
|
||||||
### Linear Axis with Nema-12 28HB40 Stepper
|
|
||||||
See [connection-plan.pdf](connection-plan.pdf)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
For this project **ESP-IDF v4.4.4** is required (with other versions it might not compile)
|
|
||||||
```bash
|
|
||||||
#download esp-idf
|
|
||||||
yay -S esp-idf
|
|
||||||
#alternatively clone the esp-idf repository from github and do `git checkout release/4.4`
|
|
||||||
|
|
||||||
#run installation script in installed folder
|
|
||||||
/opt/esp-idf/install.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
# Build
|
|
||||||
### Set up environment
|
|
||||||
```bash
|
|
||||||
source /opt/esp-idf/export.sh
|
|
||||||
```
|
|
||||||
(run once per terminal)
|
|
||||||
|
|
||||||
### Compile
|
|
||||||
```bash
|
|
||||||
cd board_single
|
|
||||||
idf.py build
|
|
||||||
```
|
|
||||||
|
|
||||||
# Flash
|
|
||||||
- connect FTDI programmer to board (VCC to VCC; TX to RX; RX to TX)
|
|
||||||
- press REST and BOOT button
|
|
||||||
- release RESET button (keep pressing boot)
|
|
||||||
- run flash command:
|
|
||||||
```bash
|
|
||||||
idf.py flash
|
|
||||||
```
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -55,6 +55,9 @@ void DendoStepper::init(uint8_t stepP, uint8_t dirP, uint8_t enP, timer_group_t
|
|||||||
|
|
||||||
void DendoStepper::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
|
uint64_t mask = (1ULL << conf.stepPin) | (1ULL << conf.dirPin) | (1ULL << conf.enPin); // put output gpio pins in bitmask
|
||||||
gpio_config_t gpio_conf = {
|
gpio_config_t gpio_conf = {
|
||||||
// config gpios
|
// config gpios
|
||||||
@@ -114,39 +117,36 @@ timer_avail:
|
|||||||
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_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)
|
esp_err_t DendoStepper::runPos(int32_t relative)
|
||||||
{
|
{
|
||||||
//TODO only enable when actually moving
|
//TODO only enable when actually moving
|
||||||
if (ctrl.status == DISABLED) // if motor is disabled, enable it
|
if (ctrl.status == DISABLED) // if motor is disabled, enable it
|
||||||
enableMotor();
|
enableMotor();
|
||||||
|
|
||||||
|
setDir(relative < 0); // set CCW if <0, else set CW
|
||||||
|
|
||||||
if (!relative) // why would u call it with 0 wtf
|
if (!relative) // why would u call it with 0 wtf
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
|
||||||
if (ctrl.status > IDLE) { //currently moving
|
if (ctrl.status > IDLE) { //currently moving
|
||||||
bool newDir = (relative < 0); // CCW if <0, else set CW
|
//ctrl.status = ctrl.status==COAST ? COAST : ACC; //stay at coast otherwise switch to ACC
|
||||||
if (ctrl.dir == newDir){ //current direction is the same
|
ctrl.stepsRemaining = ctrl.stepsToGo - ctrl.stepCnt;
|
||||||
ctrl.statusPrev = ctrl.status; //update previous status
|
calc(abs(relative) + ctrl.stepsRemaining); //calculate new velolcity profile for new+remaining steps
|
||||||
ctrl.status = ctrl.status==COAST ? COAST : ACC; //stay at coast otherwise switch to ACC
|
ESP_LOGW("DendoStepper", "EXTEND running movement (stepsRemaining: %d + stepsNew: %d - current state: %d)", ctrl.stepsRemaining, abs(relative), (int)ctrl.status);
|
||||||
calc(abs(relative + ctrl.stepsRemaining)); //calculate new velolcity profile for new+remaining steps
|
ESP_ERROR_CHECK(timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval)); // set HW timer alarm to stepinterval
|
||||||
} else { //direction has changed
|
|
||||||
//direction change not supported TODO wait for decel finish / queue?
|
|
||||||
STEP_LOGW("DendoStepper", "DIRECTION HOT-CHANGE NOT SUPPORTED - Finising previous move, this command will be ignored");
|
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else { //current state is IDLE
|
else { //current state is IDLE
|
||||||
ctrl.statusPrev = ctrl.status; //update previous status
|
//ctrl.statusPrev = ctrl.status; //update previous status
|
||||||
ctrl.status = ACC;
|
|
||||||
setDir(relative < 0); // set CCW if <0, else set CW
|
|
||||||
calc(abs(relative)); // calculate velocity profile
|
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)
|
currentPos += relative; //(target position / not actual)
|
||||||
ESP_ERROR_CHECK(timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval)); // set HW timer alarm to stepinterval
|
|
||||||
//TODO timer has to be stopped before update if already running?
|
|
||||||
ESP_ERROR_CHECK(timer_start(conf.timer_group, conf.timer_idx)); // start the timer
|
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,26 +159,31 @@ esp_err_t DendoStepper::runPosMm(int32_t relative)
|
|||||||
return runPos(relative * ctrl.stepsPerMm);
|
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)
|
esp_err_t DendoStepper::runAbs(uint32_t position)
|
||||||
{
|
{
|
||||||
if (getState() > IDLE) // we are already moving, so stop it
|
//exit if nothing to do
|
||||||
stop();
|
if (position == currentPos) return 0; //already at position
|
||||||
while (getState() > IDLE)
|
|
||||||
{
|
|
||||||
// waiting for idle, watchdog should take care of inf loop if it occurs
|
|
||||||
vTaskDelay(1);
|
|
||||||
} // shouldnt take long tho
|
|
||||||
|
|
||||||
if (position == currentPos) // we cant go anywhere
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
//calculate steps necessary
|
||||||
int32_t relativeSteps = 0;
|
int32_t relativeSteps = 0;
|
||||||
relativeSteps = (int32_t)position - currentPos;
|
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);
|
ESP_LOGI("DendoStepper", "Cur: %llu move %d", currentPos, relativeSteps);
|
||||||
return runPos(relativeSteps); // run to new position
|
return runPos(relativeSteps); // run to new position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t DendoStepper::runAbsMm(uint32_t position)
|
esp_err_t DendoStepper::runAbsMm(uint32_t position)
|
||||||
{
|
{
|
||||||
if (ctrl.stepsPerMm == 0)
|
if (ctrl.stepsPerMm == 0)
|
||||||
@@ -306,7 +311,7 @@ void DendoStepper::stop()
|
|||||||
}
|
}
|
||||||
ctrl.runInfinite = false;
|
ctrl.runInfinite = false;
|
||||||
timer_pause(conf.timer_group, conf.timer_idx); // stop the timer
|
timer_pause(conf.timer_group, conf.timer_idx); // stop the timer
|
||||||
ctrl.statusPrev = ctrl.status; //update previous status
|
//ctrl.statusPrev = ctrl.status; //update previous status
|
||||||
ctrl.status = IDLE;
|
ctrl.status = IDLE;
|
||||||
ctrl.stepCnt = 0;
|
ctrl.stepCnt = 0;
|
||||||
gpio_set_level((gpio_num_t)conf.stepPin, 0);
|
gpio_set_level((gpio_num_t)conf.stepPin, 0);
|
||||||
@@ -333,20 +338,23 @@ bool DendoStepper::xISR()
|
|||||||
|
|
||||||
ctrl.stepCnt++;
|
ctrl.stepCnt++;
|
||||||
|
|
||||||
//CUSTOM: track actual precice current position
|
////CUSTOM: track actual precice current position
|
||||||
if (ctrl.dir) {
|
//if (ctrl.dir) {
|
||||||
ctrl.posActual ++;
|
// ctrl.posActual ++;
|
||||||
} else {
|
//} else {
|
||||||
ctrl.posActual --;
|
// ctrl.posActual --;
|
||||||
}
|
//}
|
||||||
|
|
||||||
//CUSTOM: track remaining steps for eventually resuming
|
//CUSTOM: track remaining steps for eventually resuming
|
||||||
ctrl.stepsRemaining = ctrl.stepCnt - ctrl.stepCnt;
|
//xSemaphoreTake(semaphore_isrVariables, portMAX_DELAY);
|
||||||
|
//ctrl.stepsRemaining = ctrl.stepCnt - ctrl.stepCnt;
|
||||||
|
//xSemaphoreGive(semaphore_isrVariables);
|
||||||
|
|
||||||
// we are done
|
// we are done
|
||||||
if (ctrl.stepsToGo == ctrl.stepCnt && !ctrl.runInfinite)
|
if (ctrl.stepsToGo == ctrl.stepCnt && !ctrl.runInfinite)
|
||||||
{
|
{
|
||||||
timer_pause(conf.timer_group, conf.timer_idx); // stop the timer
|
timer_pause(conf.timer_group, conf.timer_idx); // stop the timer
|
||||||
ctrl.statusPrev = ctrl.status; //update previous status
|
//ctrl.statusPrev = ctrl.status; //update previous status
|
||||||
ctrl.status = IDLE;
|
ctrl.status = IDLE;
|
||||||
ctrl.stepCnt = 0;
|
ctrl.stepCnt = 0;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -355,19 +363,19 @@ bool DendoStepper::xISR()
|
|||||||
if (ctrl.stepCnt > 0 && ctrl.stepCnt < ctrl.accEnd)
|
if (ctrl.stepCnt > 0 && ctrl.stepCnt < ctrl.accEnd)
|
||||||
{ // we are accelerating
|
{ // we are accelerating
|
||||||
ctrl.currentSpeed += ctrl.accInc;
|
ctrl.currentSpeed += ctrl.accInc;
|
||||||
ctrl.statusPrev = ctrl.status; //update previous status
|
//ctrl.statusPrev = ctrl.status; //update previous status
|
||||||
ctrl.status = ACC; // we are accelerating, note that*/
|
ctrl.status = ACC; // we are accelerating, note that*/
|
||||||
}
|
}
|
||||||
else if (ctrl.stepCnt > ctrl.coastEnd && !ctrl.runInfinite)
|
else if (ctrl.stepCnt > ctrl.coastEnd && !ctrl.runInfinite)
|
||||||
{ // we must be deccelerating then
|
{ // we must be deccelerating then
|
||||||
ctrl.currentSpeed -= ctrl.decInc;
|
ctrl.currentSpeed -= ctrl.decInc;
|
||||||
ctrl.statusPrev = ctrl.status; //update previous status
|
//ctrl.statusPrev = ctrl.status; //update previous status
|
||||||
ctrl.status = DEC; // we are deccelerating
|
ctrl.status = DEC; // we are deccelerating
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ctrl.currentSpeed = ctrl.targetSpeed;
|
ctrl.currentSpeed = ctrl.targetSpeed;
|
||||||
ctrl.statusPrev = ctrl.status; //update previous status
|
//ctrl.statusPrev = ctrl.status; //update previous status
|
||||||
ctrl.status = COAST; // we are coasting
|
ctrl.status = COAST; // we are coasting
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,25 +383,38 @@ bool DendoStepper::xISR()
|
|||||||
// set alarm to calculated interval and disable pin
|
// set alarm to calculated interval and disable pin
|
||||||
GPIO.out_w1tc = (1ULL << conf.stepPin);
|
GPIO.out_w1tc = (1ULL << conf.stepPin);
|
||||||
timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval);
|
timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval);
|
||||||
ctrl.stepCnt++;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DendoStepper::calc(uint32_t targetSteps)
|
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:
|
//steps from ctrl.speed -> 0:
|
||||||
ctrl.decSteps = 0.5 * ctrl.dec * (ctrl.speed / ctrl.dec) * (ctrl.speed / ctrl.dec);
|
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:
|
//steps from 0 -> ctrl.speed:
|
||||||
//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);
|
||||||
//steps from ctrl.currentSpeed -> ctrl.speed:
|
//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;
|
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))
|
if (targetSteps < (ctrl.decSteps + ctrl.accSteps))
|
||||||
{
|
{
|
||||||
ESP_LOGI("Dendostepper", "Computing new speed");
|
ESP_LOGI("Dendostepper", "Computing new speed");
|
||||||
|
|
||||||
ctrl.speed = sqrt(2 * targetSteps * ((ctrl.dec * ctrl.acc) / (ctrl.dec + ctrl.acc)));
|
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.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.decSteps = 0.5 * ctrl.dec * (ctrl.speed / ctrl.dec) * (ctrl.speed / ctrl.dec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,13 +422,27 @@ void DendoStepper::calc(uint32_t targetSteps)
|
|||||||
ctrl.coastEnd = targetSteps - ctrl.decSteps;
|
ctrl.coastEnd = targetSteps - ctrl.decSteps;
|
||||||
ctrl.targetSpeed = ctrl.speed;
|
ctrl.targetSpeed = ctrl.speed;
|
||||||
|
|
||||||
ctrl.accInc = ctrl.targetSpeed / (double)ctrl.accSteps;
|
ctrl.accInc = (ctrl.targetSpeed - ctrl.currentSpeed) / (double)ctrl.accSteps;
|
||||||
ctrl.decInc = ctrl.targetSpeed / (double)ctrl.decSteps;
|
ctrl.decInc = ctrl.targetSpeed / (double)ctrl.decSteps;
|
||||||
|
|
||||||
ctrl.currentSpeed = ctrl.accInc;
|
//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.stepInterval = TIMER_F / ctrl.currentSpeed;
|
||||||
ctrl.stepsToGo = targetSteps;
|
ctrl.stepsToGo = targetSteps;
|
||||||
|
|
||||||
STEP_LOGI("calc", "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);
|
//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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "esp_timer.h"
|
#include "esp_timer.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
|
||||||
//#define STEP_DEBUG
|
//#define STEP_DEBUG
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ typedef struct
|
|||||||
uint32_t accSteps = 0;
|
uint32_t accSteps = 0;
|
||||||
uint32_t decSteps = 0;
|
uint32_t decSteps = 0;
|
||||||
int32_t stepsRemaining = 0;
|
int32_t stepsRemaining = 0;
|
||||||
uint64_t posActual = 0; //actual current pos incremented at every step
|
//uint64_t posActual = 0; //actual current pos incremented at every step
|
||||||
uint8_t statusPrev = DISABLED; //FIXME currently unused
|
uint8_t statusPrev = DISABLED; //FIXME currently unused
|
||||||
uint8_t status = DISABLED;
|
uint8_t status = DISABLED;
|
||||||
bool dir = CW;
|
bool dir = CW;
|
||||||
@@ -111,6 +112,7 @@ private:
|
|||||||
ctrl_var_t ctrl;
|
ctrl_var_t ctrl;
|
||||||
esp_timer_handle_t dyingTimer;
|
esp_timer_handle_t dyingTimer;
|
||||||
TaskHandle_t enTask;
|
TaskHandle_t enTask;
|
||||||
|
SemaphoreHandle_t semaphore_isrVariables = NULL;
|
||||||
uint64_t currentPos = 0; // absolute position
|
uint64_t currentPos = 0; // absolute position
|
||||||
bool timerStarted = 0;
|
bool timerStarted = 0;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 144 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 144 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 546 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 348 KiB |
@@ -1,20 +1,15 @@
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS
|
SRCS
|
||||||
"main.cpp"
|
"main.cpp"
|
||||||
"global.cpp"
|
"config.cpp"
|
||||||
"control.cpp"
|
"control.cpp"
|
||||||
"buzzer.cpp"
|
"buzzer.cpp"
|
||||||
"vfd.cpp"
|
"vfd.cpp"
|
||||||
"display.cpp"
|
"display.cpp"
|
||||||
"cutter.cpp"
|
"cutter.cpp"
|
||||||
"switchesAnalog.cpp"
|
"switchesAnalog.cpp"
|
||||||
"stepper.cpp"
|
|
||||||
"guide-stepper.cpp"
|
"guide-stepper.cpp"
|
||||||
"encoder.cpp"
|
"encoder.cpp"
|
||||||
"shutdown.cpp"
|
|
||||||
INCLUDE_DIRS
|
INCLUDE_DIRS
|
||||||
"."
|
"."
|
||||||
)
|
)
|
||||||
|
|
||||||
# colored build output (errors, warnings...)
|
|
||||||
idf_build_set_property(COMPILE_OPTIONS "-fdiagnostics-color=always" APPEND)
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "buzzer.hpp"
|
#include "buzzer.hpp"
|
||||||
#include "config.h"
|
#include "config.hpp"
|
||||||
|
|
||||||
static const char *TAG_BUZZER = "buzzer";
|
static const char *TAG_BUZZER = "buzzer";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "global.hpp"
|
#include "config.hpp"
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
|
|
||||||
//--- inputs ---
|
//--- inputs ---
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
extern "C" {
|
||||||
|
#include "driver/adc.h"
|
||||||
|
}
|
||||||
|
#include "gpio_evaluateSwitch.hpp"
|
||||||
|
#include "buzzer.hpp"
|
||||||
|
#include "switchesAnalog.hpp"
|
||||||
|
|
||||||
#include "esp_idf_version.h"
|
|
||||||
|
|
||||||
//note: global variables and objects were moved to global.hpp
|
|
||||||
|
|
||||||
//===================================
|
//===================================
|
||||||
//===== define output gpio pins =====
|
//===== define output gpio pins =====
|
||||||
@@ -27,12 +30,6 @@
|
|||||||
#define ADC_CHANNEL_POTI ADC1_CHANNEL_0
|
#define ADC_CHANNEL_POTI ADC1_CHANNEL_0
|
||||||
#define GPIO_4SW_TO_ANALOG GPIO_NUM_39
|
#define GPIO_4SW_TO_ANALOG GPIO_NUM_39
|
||||||
#define ADC_CHANNEL_4SW_TO_ANALOG ADC1_CHANNEL_3 //gpio 39
|
#define ADC_CHANNEL_4SW_TO_ANALOG ADC1_CHANNEL_3 //gpio 39
|
||||||
|
|
||||||
#define ADC_CHANNEL ADC_CHANNEL_0
|
|
||||||
//#define ADC_LOW_VOLTAGE_THRESHOLD 1000 //adc value where shut down is detected (store certain values before power loss)
|
|
||||||
#define GPIO_PIN GPIO_NUM_2
|
|
||||||
|
|
||||||
#define ADC_CHANNEL_SUPPLY_VOLTAGE ADC1_CHANNEL_7//gpio35 onboard supply voltage
|
|
||||||
//ADC1_CHANNEL_0 gpio36
|
//ADC1_CHANNEL_0 gpio36
|
||||||
//ADC1_CHANNEL_6 gpio_34
|
//ADC1_CHANNEL_6 gpio_34
|
||||||
//ADC1_CHANNEL_3 gpio_39
|
//ADC1_CHANNEL_3 gpio_39
|
||||||
@@ -51,8 +48,9 @@
|
|||||||
#define SW_PRESET3 sw_gpio_analog_3
|
#define SW_PRESET3 sw_gpio_analog_3
|
||||||
#define SW_CUT sw_gpio_33
|
#define SW_CUT sw_gpio_33
|
||||||
#define SW_AUTO_CUT sw_gpio_32
|
#define SW_AUTO_CUT sw_gpio_32
|
||||||
|
|
||||||
|
//unused but already available evaluated inputs
|
||||||
//#define ? sw_gpio_34
|
//#define ? sw_gpio_34
|
||||||
//note: actual objects are created in global.cpp
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +70,6 @@
|
|||||||
#define DISPLAY_PIN_NUM_CLK GPIO_NUM_22
|
#define DISPLAY_PIN_NUM_CLK GPIO_NUM_22
|
||||||
#define DISPLAY_PIN_NUM_CS GPIO_NUM_27
|
#define DISPLAY_PIN_NUM_CS GPIO_NUM_27
|
||||||
#define DISPLAY_DELAY 2000
|
#define DISPLAY_DELAY 2000
|
||||||
#define DISPLAY_BRIGHTNESS 8
|
|
||||||
|
|
||||||
//--------------------------
|
//--------------------------
|
||||||
//----- encoder config -----
|
//----- encoder config -----
|
||||||
@@ -89,39 +86,53 @@
|
|||||||
//--------------------------
|
//--------------------------
|
||||||
//enable stepper test mode (dont start control and encoder task)
|
//enable stepper test mode (dont start control and encoder task)
|
||||||
//#define STEPPER_TEST
|
//#define STEPPER_TEST
|
||||||
//pins
|
#define STEPPER_STEP_PIN GPIO_NUM_18 //mos1
|
||||||
#define STEPPER_STEP_PIN GPIO_NUM_18 //mos1
|
#define STEPPER_DIR_PIN GPIO_NUM_16 //ST3
|
||||||
#define STEPPER_DIR_PIN GPIO_NUM_16 //ST3
|
#define STEPPER_EN_PIN GPIO_NUM_0 //not connected (-> stepper always on)
|
||||||
//driver settings
|
//more detailed options for testing are currently defined in guide-stepper.cpp
|
||||||
#define STEPPER_STEPS_PER_MM (200/2) //steps/mm (steps-per-rot / spindle-slope)
|
|
||||||
#define STEPPER_SPEED_DEFAULT 25 //mm/s
|
|
||||||
#define STEPPER_SPEED_MIN 4 //mm/s - speed threshold at which stepper immediately starts/stops
|
|
||||||
#define STEPPER_ACCEL_INC 3 //steps/s increment per cycle
|
|
||||||
#define STEPPER_DECEL_INC 7 //steps/s decrement per cycle
|
|
||||||
//options affecting movement are currently defined in guide-stepper.cpp
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------
|
//--------------------------
|
||||||
//------ calibration -------
|
//------ calibration -------
|
||||||
//--------------------------
|
//--------------------------
|
||||||
//enable mode encoder test for calibration (determine ENCODER_STEPS_PER_METER)
|
//enable mode encoder test for calibration
|
||||||
//if defined, displays always show length and steps instead of the normal messages
|
//if defined, displays always show length and steps instead of the normal messages
|
||||||
//#define ENCODER_TEST
|
//#define ENCODER_TEST
|
||||||
//TODO: add way to calibrate without flashing -> enter calibration mode with certain button sequence, enter steps-per-meter with poti, store in nvs
|
|
||||||
|
|
||||||
//steps per meter
|
//steps per meter
|
||||||
//this value is determined experimentally while ENCODER_TEST is enabled
|
#define ENCODER_STEPS_PER_METER 2127 //roll-v3-gummi-86.6mm - d=89.8mm
|
||||||
//#define ENCODER_STEPS_PER_METER 2127 //until 2024.03.13 roll-v3-gummi-86.6mm - d=89.8mm
|
|
||||||
#define ENCODER_STEPS_PER_METER 2118 //2024.03.13 roll-v3-gummi measured 86.5mm
|
|
||||||
|
|
||||||
//millimeters added to target length
|
//millimetres added to target length
|
||||||
//to ensure that length does not fall short when spool slightly rotates back after stop
|
//to ensure that length does not fall short when spool slightly rotates back after stop
|
||||||
#define TARGET_LENGTH_OFFSET 0
|
#define TARGET_LENGTH_OFFSET 0
|
||||||
|
|
||||||
//millimeters lengthNow can be below lengthTarget to still stay in target_reached state
|
//millimetres lengthNow can be below lengthTarget to still stay in target_reached state
|
||||||
#define TARGET_REACHED_TOLERANCE 5
|
#define TARGET_REACHED_TOLERANCE 5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================
|
||||||
|
//===== global variables =====
|
||||||
|
//============================
|
||||||
|
//create global evaluated switch objects
|
||||||
|
//--- switches on digital gpio pins ---
|
||||||
|
//extern gpio_evaluatedSwitch sw_gpio_39;
|
||||||
|
extern gpio_evaluatedSwitch sw_gpio_34;
|
||||||
|
extern gpio_evaluatedSwitch sw_gpio_32;
|
||||||
|
extern gpio_evaluatedSwitch sw_gpio_33;
|
||||||
|
extern gpio_evaluatedSwitch sw_gpio_25;
|
||||||
|
extern gpio_evaluatedSwitch sw_gpio_26;
|
||||||
|
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
|
||||||
|
extern buzzer_t buzzer;
|
||||||
169
main/control.cpp
169
main/control.cpp
@@ -1,47 +1,20 @@
|
|||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
#include <esp_idf_version.h>
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "driver/adc.h"
|
|
||||||
|
|
||||||
#include "max7219.h"
|
|
||||||
|
|
||||||
}
|
|
||||||
#include <cmath>
|
|
||||||
#include "config.h"
|
|
||||||
#include "gpio_evaluateSwitch.hpp"
|
|
||||||
#include "gpio_adc.hpp"
|
|
||||||
#include "buzzer.hpp"
|
|
||||||
#include "vfd.hpp"
|
|
||||||
#include "display.hpp"
|
|
||||||
#include "cutter.hpp"
|
|
||||||
#include "encoder.hpp"
|
|
||||||
#include "guide-stepper.hpp"
|
|
||||||
#include "global.hpp"
|
|
||||||
#include "control.hpp"
|
#include "control.hpp"
|
||||||
|
#include "encoder.hpp"
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------
|
//====================
|
||||||
//--------------- variables ---------------
|
//==== variables =====
|
||||||
//-----------------------------------------
|
//====================
|
||||||
static const char *TAG = "control"; //tag for logging
|
static const char *TAG = "control"; //tag for logging
|
||||||
|
|
||||||
//control
|
|
||||||
const char* systemStateStr[7] = {"COUNTING", "WINDING_START", "WINDING", "TARGET_REACHED", "AUTO_CUT_WAITING", "CUTTING", "MANUAL"};
|
const char* systemStateStr[7] = {"COUNTING", "WINDING_START", "WINDING", "TARGET_REACHED", "AUTO_CUT_WAITING", "CUTTING", "MANUAL"};
|
||||||
systemState_t controlState = systemState_t::COUNTING;
|
systemState_t controlState = systemState_t::COUNTING;
|
||||||
static uint32_t timestamp_lastStateChange = 0;
|
static uint32_t timestamp_changedState = 0;
|
||||||
|
|
||||||
//display
|
|
||||||
static char buf_disp1[10];// 8 digits + decimal point + \0
|
static char buf_disp1[10];// 8 digits + decimal point + \0
|
||||||
static char buf_disp2[10];// 8 digits + decimal point + \0
|
static char buf_disp2[10];// 8 digits + decimal point + \0
|
||||||
static char buf_tmp[15];
|
static char buf_tmp[15];
|
||||||
|
|
||||||
//track length
|
|
||||||
static int lengthNow = 0; //length measured in mm
|
static int lengthNow = 0; //length measured in mm
|
||||||
static int lengthTarget = 5000; //default target length in mm
|
static int lengthTarget = 5000; //default target length in mm
|
||||||
static int lengthRemaining = 0; //(target - now) length needed for reaching the target
|
static int lengthRemaining = 0; //(target - now) length needed for reaching the target
|
||||||
@@ -55,14 +28,7 @@ static uint32_t autoCut_delayMs = 2500; //TODO add this to config
|
|||||||
static bool autoCutEnabled = false; //store state of toggle switch (no hotswitch)
|
static bool autoCutEnabled = false; //store state of toggle switch (no hotswitch)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------
|
|
||||||
//--------------- functions ---------------
|
|
||||||
//-----------------------------------------
|
|
||||||
|
|
||||||
//========================
|
|
||||||
//===== change State =====
|
//===== change State =====
|
||||||
//========================
|
|
||||||
//function for changing the controlState with log output
|
//function for changing the controlState with log output
|
||||||
void changeState (systemState_t stateNew) {
|
void changeState (systemState_t stateNew) {
|
||||||
//only proceed when state actually changed
|
//only proceed when state actually changed
|
||||||
@@ -74,21 +40,18 @@ void changeState (systemState_t stateNew) {
|
|||||||
//change state
|
//change state
|
||||||
controlState = stateNew;
|
controlState = stateNew;
|
||||||
//update timestamp
|
//update timestamp
|
||||||
timestamp_lastStateChange = esp_log_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
|
//returns true when stopped, false when no action
|
||||||
//and takes according action if so (used in multiple states)
|
|
||||||
//returns true when stop condition was met, false when no action required
|
|
||||||
bool handleStopCondition(handledDisplay * displayTop, handledDisplay * displayBot){
|
bool handleStopCondition(handledDisplay * displayTop, handledDisplay * displayBot){
|
||||||
//--- stop conditions ---
|
//--- stop conditions ---
|
||||||
//stop conditions that are checked in any mode
|
//stop conditions that are checked in any mode
|
||||||
//target reached -> reached state, stop motor, display message
|
//target reached
|
||||||
if (lengthRemaining <= 0 ) {
|
if (lengthRemaining <= 0 ) {
|
||||||
changeState(systemState_t::TARGET_REACHED);
|
changeState(systemState_t::TARGET_REACHED);
|
||||||
vfd_setState(false);
|
vfd_setState(false);
|
||||||
@@ -97,7 +60,7 @@ bool handleStopCondition(handledDisplay * displayTop, handledDisplay * displayBo
|
|||||||
buzzer.beep(2, 100, 100);
|
buzzer.beep(2, 100, 100);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//start button released -> idle state, stop motor, display message
|
//start button released
|
||||||
else if (SW_START.state == false) {
|
else if (SW_START.state == false) {
|
||||||
changeState(systemState_t::COUNTING);
|
changeState(systemState_t::COUNTING);
|
||||||
vfd_setState(false);
|
vfd_setState(false);
|
||||||
@@ -111,11 +74,8 @@ bool handleStopCondition(handledDisplay * displayTop, handledDisplay * displayBo
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===================================
|
|
||||||
//===== set dynamic speed level =====
|
//===== set dynamic speed level =====
|
||||||
//===================================
|
//function that sets the vfd speed level dynamicly depending on the remaining distance
|
||||||
//function that sets the vfd speed level dynamically depending on the remaining distance
|
|
||||||
//closer to target -> slower
|
//closer to target -> slower
|
||||||
void setDynSpeedLvl(uint8_t lvlMax = 3){
|
void setDynSpeedLvl(uint8_t lvlMax = 3){
|
||||||
uint8_t lvl;
|
uint8_t lvl;
|
||||||
@@ -143,30 +103,31 @@ void setDynSpeedLvl(uint8_t lvlMax = 3){
|
|||||||
//========================
|
//========================
|
||||||
//===== control task =====
|
//===== control task =====
|
||||||
//========================
|
//========================
|
||||||
//task that controls the entire machine
|
|
||||||
void task_control(void *pvParameter)
|
void task_control(void *pvParameter)
|
||||||
{
|
{
|
||||||
//-- initialize display --
|
|
||||||
|
//initialize display
|
||||||
max7219_t two7SegDisplays = display_init();
|
max7219_t two7SegDisplays = display_init();
|
||||||
//create two separate custom handled display instances
|
//create two separate handled display instances
|
||||||
handledDisplay displayTop(two7SegDisplays, 0);
|
handledDisplay displayTop(two7SegDisplays, 0);
|
||||||
handledDisplay displayBot(two7SegDisplays, 8);
|
handledDisplay displayBot(two7SegDisplays, 8);
|
||||||
|
|
||||||
//-- display welcome msg --
|
//--- display welcome msg ---
|
||||||
//display welcome message on two 7 segment displays
|
//display welcome message on two 7 segment displays
|
||||||
//currently show name and date and scrolling 'hello'
|
//currently show name and date and scrolling 'hello'
|
||||||
display_ShowWelcomeMsg(two7SegDisplays);
|
display_ShowWelcomeMsg(two7SegDisplays);
|
||||||
|
|
||||||
// ##############################
|
|
||||||
// ######## control loop ########
|
//================
|
||||||
// ##############################
|
//===== loop =====
|
||||||
// repeatedly handle the machine
|
//================
|
||||||
while(1){
|
while(1){
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
//-----------------------------
|
||||||
//------ handle switches ------
|
//------ handle switches ------
|
||||||
//run handle functions for all switches used here
|
//-----------------------------
|
||||||
|
//run handle functions for all switches
|
||||||
SW_START.handle();
|
SW_START.handle();
|
||||||
SW_RESET.handle();
|
SW_RESET.handle();
|
||||||
SW_SET.handle();
|
SW_SET.handle();
|
||||||
@@ -177,23 +138,27 @@ void task_control(void *pvParameter)
|
|||||||
SW_AUTO_CUT.handle();
|
SW_AUTO_CUT.handle();
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
//------ handle cutter ------
|
//------ handle cutter ------
|
||||||
//TODO: separate task for cutter?
|
//---------------------------
|
||||||
cutter_handle();
|
cutter_handle();
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------
|
||||||
//------ rotary encoder ------
|
//------ rotary encoder ------
|
||||||
//get current length since last reset
|
//----------------------------
|
||||||
|
//--- get current length since last reset ---
|
||||||
lengthNow = encoder_getLenMm();
|
lengthNow = encoder_getLenMm();
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
//--------- buttons ---------
|
//--------- buttons ---------
|
||||||
//#### RESET switch ####
|
//---------------------------
|
||||||
|
//--- RESET switch ---
|
||||||
if (SW_RESET.risingEdge) {
|
if (SW_RESET.risingEdge) {
|
||||||
//dont reset when press used for stopping pending auto-cut
|
//dont reset when press used for stopping pending auto-cut
|
||||||
if (controlState != systemState_t::AUTO_CUT_WAITING) {
|
if (controlState != systemState_t::AUTO_CUT_WAITING) {
|
||||||
guide_moveToZero(); //move axis guiding the cable to start position
|
encoder_reset();
|
||||||
encoder_reset(); //reset length measurement
|
|
||||||
lengthNow = 0;
|
lengthNow = 0;
|
||||||
buzzer.beep(1, 700, 100);
|
buzzer.beep(1, 700, 100);
|
||||||
displayTop.blink(2, 100, 100, "1ST ");
|
displayTop.blink(2, 100, 100, "1ST ");
|
||||||
@@ -202,7 +167,7 @@ void task_control(void *pvParameter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//### CUT switch ####
|
//--- CUT switch ---
|
||||||
//start cut cycle immediately
|
//start cut cycle immediately
|
||||||
if (SW_CUT.risingEdge) {
|
if (SW_CUT.risingEdge) {
|
||||||
//stop cutter if already running
|
//stop cutter if already running
|
||||||
@@ -225,7 +190,7 @@ void task_control(void *pvParameter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#### AUTO_CUT toggle sw ####
|
//--- AUTO_CUT toggle sw ---
|
||||||
//beep at change
|
//beep at change
|
||||||
if (SW_AUTO_CUT.risingEdge) {
|
if (SW_AUTO_CUT.risingEdge) {
|
||||||
buzzer.beep(2, 100, 50);
|
buzzer.beep(2, 100, 50);
|
||||||
@@ -244,7 +209,7 @@ void task_control(void *pvParameter)
|
|||||||
autoCutEnabled = false;
|
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 != systemState_t::MANUAL ) {
|
if ( SW_PRESET2.state && (SW_PRESET1.state || SW_PRESET3.state) && controlState != systemState_t::MANUAL ) {
|
||||||
//enable manual control
|
//enable manual control
|
||||||
@@ -252,7 +217,7 @@ void task_control(void *pvParameter)
|
|||||||
buzzer.beep(3, 100, 60);
|
buzzer.beep(3, 100, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
//##### SET switch #####
|
//--- 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
|
||||||
@@ -288,7 +253,7 @@ void task_control(void *pvParameter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//##### target length preset buttons #####
|
//--- target length presets ---
|
||||||
if (controlState != systemState_t::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 = 5000;
|
lengthTarget = 5000;
|
||||||
@@ -308,17 +273,16 @@ void task_control(void *pvParameter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------
|
//---------------------------
|
||||||
//--------- control ---------
|
//--------- control ---------
|
||||||
//---------------------------
|
//---------------------------
|
||||||
//statemachine handling the sequential winding process
|
//calculate length difference
|
||||||
|
|
||||||
//calculate current length difference
|
|
||||||
lengthRemaining = lengthTarget - lengthNow + TARGET_LENGTH_OFFSET;
|
lengthRemaining = lengthTarget - lengthNow + TARGET_LENGTH_OFFSET;
|
||||||
|
|
||||||
//--- statemachine ---
|
//--- statemachine ---
|
||||||
switch (controlState) {
|
switch (controlState) {
|
||||||
case systemState_t::COUNTING: //no motor action, just show current length on display
|
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 already at target
|
//TODO check stop condition before starting - prevents motor from starting 2 cycles when already at target
|
||||||
//--- start winding to length ---
|
//--- start winding to length ---
|
||||||
@@ -334,7 +298,6 @@ void task_control(void *pvParameter)
|
|||||||
case systemState_t::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)
|
||||||
//switch to WINDING state (full speed) when 3s have passed
|
|
||||||
if (esp_log_timestamp() - timestamp_motorStarted > 3000) {
|
if (esp_log_timestamp() - timestamp_motorStarted > 3000) {
|
||||||
changeState(systemState_t::WINDING);
|
changeState(systemState_t::WINDING);
|
||||||
}
|
}
|
||||||
@@ -344,23 +307,23 @@ void task_control(void *pvParameter)
|
|||||||
|
|
||||||
case systemState_t::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(); //set motor speed, 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 systemState_t::TARGET_REACHED: //prevent further motor rotation and start auto-cut
|
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 ( lengthNow < lengthTarget - TARGET_REACHED_TOLERANCE ) {
|
if ( lengthNow < lengthTarget - TARGET_REACHED_TOLERANCE ) {
|
||||||
changeState(systemState_t::COUNTING);
|
changeState(systemState_t::COUNTING);
|
||||||
}
|
}
|
||||||
//initiate countdown to auto-cut if enabled
|
//switch initiate countdown to auto-cut
|
||||||
else if ( (autoCutEnabled)
|
else if ( (autoCutEnabled)
|
||||||
&& (esp_log_timestamp() - timestamp_lastStateChange > 300) ) { //wait for dislay msg "reached" to finish
|
&& (esp_log_timestamp() - timestamp_changedState > 300) ) { //wait for dislay msg "reached" to finish
|
||||||
changeState(systemState_t::AUTO_CUT_WAITING);
|
changeState(systemState_t::AUTO_CUT_WAITING);
|
||||||
}
|
}
|
||||||
//show msg when trying to start, but target is already reached (-> reset button has to be pressed)
|
//show msg when trying to start, but target is reached
|
||||||
if (SW_START.risingEdge) {
|
if (SW_START.risingEdge) {
|
||||||
buzzer.beep(2, 50, 30);
|
buzzer.beep(2, 50, 30);
|
||||||
displayTop.blink(2, 600, 500, " S0LL ");
|
displayTop.blink(2, 600, 500, " S0LL ");
|
||||||
@@ -368,8 +331,9 @@ void task_control(void *pvParameter)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case systemState_t::AUTO_CUT_WAITING: //handle delayed start of cut
|
case systemState_t::AUTO_CUT_WAITING:
|
||||||
cut_msRemaining = autoCut_delayMs - (esp_log_timestamp() - timestamp_lastStateChange);
|
//handle delayed start of cut
|
||||||
|
cut_msRemaining = autoCut_delayMs - (esp_log_timestamp() - timestamp_changedState);
|
||||||
//- countdown stop conditions -
|
//- countdown stop conditions -
|
||||||
//stop with any button
|
//stop with any button
|
||||||
if (!autoCutEnabled
|
if (!autoCutEnabled
|
||||||
@@ -393,14 +357,13 @@ void task_control(void *pvParameter)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case systemState_t::CUTTING: //prevent any action while cutter is active
|
case systemState_t::CUTTING:
|
||||||
//exit when finished cutting
|
//exit when finished cutting
|
||||||
if (cutter_isRunning() == false) {
|
if (cutter_isRunning() == false) {
|
||||||
//TODO stop if start buttons released?
|
//TODO stop if start buttons released?
|
||||||
changeState(systemState_t::COUNTING);
|
changeState(systemState_t::COUNTING);
|
||||||
//TODO reset automatically or wait for manual reset?
|
//TODO reset automatically or wait for manual reset?
|
||||||
guide_moveToZero(); //move axis guiding the cable to start position
|
encoder_reset();
|
||||||
encoder_reset(); //reset length measurement
|
|
||||||
lengthNow = 0;
|
lengthNow = 0;
|
||||||
buzzer.beep(1, 700, 100);
|
buzzer.beep(1, 700, 100);
|
||||||
}
|
}
|
||||||
@@ -437,34 +400,30 @@ void task_control(void *pvParameter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENCODER_TEST
|
|
||||||
//--------------------------
|
//--------------------------
|
||||||
//------ encoder test ------
|
//------ encoder test ------
|
||||||
//--------------------------
|
//--------------------------
|
||||||
//mode for calibrating the cable length measurement (determine ENCODER_STEPS_PER_METER in config.h)
|
#ifdef ENCODER_TEST
|
||||||
//run display handle functions
|
//run display handle functions
|
||||||
displayTop.handle();
|
displayTop.handle();
|
||||||
displayBot.handle();
|
displayBot.handle();
|
||||||
//-- show encoder steps on display1 ---
|
//-- show encoder steps on display1 ---
|
||||||
sprintf(buf_disp1, "EN %05d", encoder_getSteps()); //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
|
||||||
displayBot.showString(buf_disp2);
|
displayBot.showString(buf_disp2);
|
||||||
//--- beep every 0.5m ---
|
//--- beep every 1m ---
|
||||||
//note: only works precisely in forward/positive direction, in reverse it it beeps by tolerance too early
|
//note: only works precicely in forward/positive direction
|
||||||
static int lengthBeeped = 0;
|
if (lengthNow % 1000 < 50) { //with tolerance in case of missed exact value
|
||||||
if (lengthNow % 500 < 50) { //with tolerance in case of missed exact value
|
if (fabs(lengthNow - lengthBeeped) >= 900) { //dont beep multiple times at same meter
|
||||||
if (fabs(lengthNow - lengthBeeped) >= 400) { //dont beep multiple times at same distance
|
//TODO: add case for reverse direction. currently beeps 0.1 too early
|
||||||
//TODO: add case for reverse direction. currently beeps 50mm too early
|
buzzer.beep(1, 400, 100 );
|
||||||
if (lengthNow % 1000 < 50) // 1m beep
|
|
||||||
buzzer.beep(1, 400, 100);
|
|
||||||
else // 0.5m beep
|
|
||||||
buzzer.beep(1, 200, 100);
|
|
||||||
lengthBeeped = lengthNow;
|
lengthBeeped = lengthNow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else //not in encoder calibration mode
|
#else
|
||||||
|
|
||||||
//--------------------------
|
//--------------------------
|
||||||
//-------- display1 --------
|
//-------- display1 --------
|
||||||
@@ -484,6 +443,7 @@ void task_control(void *pvParameter)
|
|||||||
displayTop.showString(buf_disp1);
|
displayTop.showString(buf_disp1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------
|
//--------------------------
|
||||||
//-------- display2 --------
|
//-------- display2 --------
|
||||||
//--------------------------
|
//--------------------------
|
||||||
@@ -516,7 +476,6 @@ void task_control(void *pvParameter)
|
|||||||
displayBot.showString(buf_tmp);
|
displayBot.showString(buf_tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // end else ifdef ENCODER_TEST
|
|
||||||
|
|
||||||
//----------------------------
|
//----------------------------
|
||||||
//------- control lamp -------
|
//------- control lamp -------
|
||||||
@@ -533,6 +492,10 @@ void task_control(void *pvParameter)
|
|||||||
gpio_set_level(GPIO_LAMP, 0);
|
gpio_set_level(GPIO_LAMP, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} //end while(1)
|
|
||||||
|
|
||||||
} //end task_control
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
#include <esp_idf_version.h>
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "driver/adc.h"
|
||||||
|
|
||||||
|
#include "max7219.h"
|
||||||
|
|
||||||
|
}
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "gpio_evaluateSwitch.hpp"
|
||||||
|
#include "gpio_adc.hpp"
|
||||||
|
#include "buzzer.hpp"
|
||||||
|
#include "vfd.hpp"
|
||||||
|
#include "display.hpp"
|
||||||
|
#include "cutter.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//enum describing the state of the system
|
//enum describing the state of the system
|
||||||
enum class systemState_t {COUNTING, WINDING_START, WINDING, TARGET_REACHED, AUTO_CUT_WAITING, CUTTING, MANUAL};
|
enum class systemState_t {COUNTING, WINDING_START, WINDING, TARGET_REACHED, AUTO_CUT_WAITING, CUTTING, MANUAL};
|
||||||
|
|
||||||
//array with enum as strings for logging states
|
//array with enum as strings for logging states
|
||||||
extern const char* systemStateStr[7];
|
extern const char* systemStateStr[7];
|
||||||
|
|
||||||
|
|
||||||
//task that controls the entire machine (has to be created as task in main function)
|
//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);
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#include "cutter.hpp"
|
#include "cutter.hpp"
|
||||||
#include "config.h"
|
|
||||||
#include "global.hpp"
|
|
||||||
|
|
||||||
const char* cutter_stateStr[5] = {"IDLE", "START", "CUTTING", "CANCELED", "TIMEOUT"}; //define strings for logging the state
|
const char* cutter_stateStr[5] = {"IDLE", "START", "CUTTING", "CANCELED", "TIMEOUT"}; //define strings for logging the state
|
||||||
|
|
||||||
@@ -41,6 +39,7 @@ void cutter_stop(){
|
|||||||
if(cutter_state != cutter_state_t::IDLE){
|
if(cutter_state != cutter_state_t::IDLE){
|
||||||
setState(cutter_state_t::CANCELED);
|
setState(cutter_state_t::CANCELED);
|
||||||
}
|
}
|
||||||
|
//starts motor on state change
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -132,6 +131,7 @@ void cutter_handle(){
|
|||||||
//SW_CUTTER_POS.minOnMs = 10;
|
//SW_CUTTER_POS.minOnMs = 10;
|
||||||
//SW_CUTTER_POS.minOffMs = 10;
|
//SW_CUTTER_POS.minOffMs = 10;
|
||||||
|
|
||||||
|
|
||||||
switch(cutter_state){
|
switch(cutter_state){
|
||||||
case cutter_state_t::IDLE:
|
case cutter_state_t::IDLE:
|
||||||
case cutter_state_t::TIMEOUT:
|
case cutter_state_t::TIMEOUT:
|
||||||
@@ -142,13 +142,14 @@ void cutter_handle(){
|
|||||||
case cutter_state_t::START:
|
case cutter_state_t::START:
|
||||||
//--- moved away from idle position ---
|
//--- moved away from idle position ---
|
||||||
//if (gpio_get_level(GPIO_CUTTER_POS_SW) == 0){ //contact closed
|
//if (gpio_get_level(GPIO_CUTTER_POS_SW) == 0){ //contact closed
|
||||||
if (SW_CUTTER_POS.state == true) { //contact closed -> not at idle pos anymore
|
if (SW_CUTTER_POS.state == true) { //contact closed -> not at idle pos
|
||||||
setState(cutter_state_t::CUTTING);
|
setState(cutter_state_t::CUTTING);
|
||||||
}
|
}
|
||||||
//--- timeout ---
|
//--- timeout ---
|
||||||
else {
|
else {
|
||||||
checkTimeout();
|
checkTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cutter_state_t::CUTTING:
|
case cutter_state_t::CUTTING:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include "display.hpp"
|
#include "display.hpp"
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
//=== variables ===
|
//=== variables ===
|
||||||
static const char *TAG = "display"; //tag for logging
|
static const char *TAG = "display"; //tag for logging
|
||||||
@@ -35,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, DISPLAY_BRIGHTNESS));
|
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");
|
||||||
@@ -51,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 15.03.2024");
|
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
|
||||||
@@ -65,7 +64,7 @@ void display_ShowWelcomeMsg(max7219_t dev){
|
|||||||
//noticed rare bug that one display does not initialize / is not configured correctly after start
|
//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
|
//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_init(&dev));
|
||||||
ESP_ERROR_CHECK(max7219_set_brightness(&dev, DISPLAY_BRIGHTNESS));
|
ESP_ERROR_CHECK(max7219_set_brightness(&dev, 8)); //TODO add this to config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -84,9 +83,9 @@ handledDisplay::handledDisplay(max7219_t displayDevice, uint8_t posStart_f) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================================
|
//--------------------------------
|
||||||
//========== showString ==========
|
//---------- showString ----------
|
||||||
//================================
|
//--------------------------------
|
||||||
//function that displays a given string on the display
|
//function that displays a given string on the display
|
||||||
void handledDisplay::showString(const char * buf, uint8_t pos_f){
|
void handledDisplay::showString(const char * buf, uint8_t pos_f){
|
||||||
//calculate actual absolute position
|
//calculate actual absolute position
|
||||||
@@ -104,11 +103,11 @@ void handledDisplay::showString(const char * buf, uint8_t pos_f){
|
|||||||
|
|
||||||
|
|
||||||
//TODO: blinkStrings() and blink() are very similar - can be optimized?
|
//TODO: blinkStrings() and blink() are very similar - can be optimized?
|
||||||
//only difficulty is the reset behaivor of blinkStrings through showString (blink does not reset)
|
//only difficulty currently is the reset behaivor of blinkStrings through showString (blink does not reset)
|
||||||
|
|
||||||
//==================================
|
//----------------------------------
|
||||||
//========== blinkStrings ==========
|
//---------- blinkStrings ----------
|
||||||
//==================================
|
//----------------------------------
|
||||||
//function switches between two strings in a given interval
|
//function switches between two strings in a given interval
|
||||||
void handledDisplay::blinkStrings(const char * strOn_f, const char * strOff_f, uint32_t msOn_f, uint32_t msOff_f){
|
void handledDisplay::blinkStrings(const char * strOn_f, const char * strOff_f, uint32_t msOn_f, uint32_t msOff_f){
|
||||||
//copy/update variables
|
//copy/update variables
|
||||||
@@ -131,9 +130,9 @@ void handledDisplay::blinkStrings(const char * strOn_f, const char * strOff_f, u
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===============================
|
//-------------------------------
|
||||||
//============ blink ============
|
//------------ blink ------------
|
||||||
//===============================
|
//-------------------------------
|
||||||
//function triggers certain count and interval of off durations
|
//function triggers certain count and interval of off durations
|
||||||
void handledDisplay::blink(uint8_t count_f, uint32_t msOn_f, uint32_t msOff_f, const char * strOff_f) {
|
void handledDisplay::blink(uint8_t count_f, uint32_t msOn_f, uint32_t msOff_f, const char * strOff_f) {
|
||||||
//copy/update parameters
|
//copy/update parameters
|
||||||
@@ -157,9 +156,9 @@ void handledDisplay::blink(uint8_t count_f, uint32_t msOn_f, uint32_t msOff_f, c
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================================
|
//--------------------------------
|
||||||
//============ handle ============
|
//------------ handle ------------
|
||||||
//================================
|
//--------------------------------
|
||||||
//function that handles time based modes
|
//function that handles time based modes
|
||||||
//writes text to the 7 segment display depending on the current mode
|
//writes text to the 7 segment display depending on the current mode
|
||||||
void handledDisplay::handle() {
|
void handledDisplay::handle() {
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ extern "C"
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
|
||||||
//function for initializing the display using configuration from macros in config.h
|
//function for initializing the display using configuration from macros in config.hpp
|
||||||
max7219_t display_init();
|
max7219_t display_init();
|
||||||
|
|
||||||
//show welcome message on the entire display
|
//show welcome message on the entire display
|
||||||
@@ -43,8 +44,8 @@ class handledDisplay {
|
|||||||
//TODO: blinkStrings and blink are very similar - optimize?
|
//TODO: blinkStrings and blink are very similar - optimize?
|
||||||
//TODO: add 'scroll string' method
|
//TODO: add 'scroll string' method
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
//--- variables ---
|
//--- variables ---
|
||||||
//config
|
//config
|
||||||
max7219_t dev;
|
max7219_t dev;
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "encoder.hpp"
|
#include "encoder.hpp"
|
||||||
#include "config.h"
|
|
||||||
#include "global.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------
|
//----------------------------
|
||||||
@@ -19,14 +17,10 @@ static rotary_encoder_info_t encoder; //encoder device/info
|
|||||||
QueueHandle_t encoder_queue = NULL; //encoder event queue
|
QueueHandle_t encoder_queue = NULL; //encoder event queue
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------
|
//-------------------------
|
||||||
//------- functions -------
|
//------- functions -------
|
||||||
//-------------------------
|
//-------------------------
|
||||||
|
//--- encoder_init ---
|
||||||
//======================
|
|
||||||
//==== encoder_init ====
|
|
||||||
//======================
|
|
||||||
//initialize encoder and return event queue
|
//initialize encoder and return event queue
|
||||||
QueueHandle_t encoder_init(){
|
QueueHandle_t encoder_init(){
|
||||||
// esp32-rotary-encoder requires that the GPIO ISR service is installed before calling rotary_encoder_register()
|
// esp32-rotary-encoder requires that the GPIO ISR service is installed before calling rotary_encoder_register()
|
||||||
@@ -47,9 +41,7 @@ QueueHandle_t encoder_init(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//========================
|
//--- encoder_getSteps ---
|
||||||
//=== encoder_getSteps ===
|
|
||||||
//========================
|
|
||||||
//get steps counted since last reset
|
//get steps counted since last reset
|
||||||
int encoder_getSteps(){
|
int encoder_getSteps(){
|
||||||
// Poll current position and direction
|
// Poll current position and direction
|
||||||
@@ -60,18 +52,14 @@ int encoder_getSteps(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//========================
|
//--- encoder_getLenMm ---
|
||||||
//=== encoder_getLenMm ===
|
|
||||||
//========================
|
|
||||||
//get current length in Mm since last reset
|
//get current length in Mm since last reset
|
||||||
int encoder_getLenMm(){
|
int encoder_getLenMm(){
|
||||||
return (float)encoder_getSteps() * 1000 / ENCODER_STEPS_PER_METER;
|
return (float)encoder_getSteps() * 1000 / ENCODER_STEPS_PER_METER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//=======================
|
//--- encoder_reset ---
|
||||||
//==== encoder_reset ====
|
|
||||||
//=======================
|
|
||||||
//reset counted steps / length to 0
|
//reset counted steps / length to 0
|
||||||
void encoder_reset(){
|
void encoder_reset(){
|
||||||
rotary_encoder_reset(&encoder);
|
rotary_encoder_reset(&encoder);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ extern "C" {
|
|||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
|
||||||
|
|
||||||
//----------------------------
|
//----------------------------
|
||||||
@@ -33,6 +34,7 @@ int encoder_getSteps();
|
|||||||
int encoder_getLenMm();
|
int encoder_getLenMm();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--- encoder_reset ---
|
//--- encoder_reset ---
|
||||||
//reset counted steps / length to 0
|
//reset counted steps / length to 0
|
||||||
void encoder_reset();
|
void encoder_reset();
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "driver/adc.h"
|
|
||||||
}
|
|
||||||
#include "gpio_evaluateSwitch.hpp"
|
|
||||||
#include "buzzer.hpp"
|
|
||||||
#include "switchesAnalog.hpp"
|
|
||||||
|
|
||||||
//note: in the actual code macro variables to these objects from config.h are used as the objects names
|
|
||||||
|
|
||||||
//============================
|
|
||||||
//===== global variables =====
|
|
||||||
//============================
|
|
||||||
//create global evaluated switch objects for all available pins
|
|
||||||
//--- switches on digital gpio pins ---
|
|
||||||
//extern gpio_evaluatedSwitch sw_gpio_39;
|
|
||||||
extern gpio_evaluatedSwitch sw_gpio_34;
|
|
||||||
extern gpio_evaluatedSwitch sw_gpio_32;
|
|
||||||
extern gpio_evaluatedSwitch sw_gpio_33;
|
|
||||||
extern gpio_evaluatedSwitch sw_gpio_25;
|
|
||||||
extern gpio_evaluatedSwitch sw_gpio_26;
|
|
||||||
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
|
|
||||||
extern buzzer_t buzzer;
|
|
||||||
@@ -5,128 +5,97 @@ extern "C"
|
|||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "driver/adc.h"
|
#include "driver/adc.h"
|
||||||
#include "freertos/queue.h"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "stepper.hpp"
|
#include "DendoStepper.h"
|
||||||
#include "config.h"
|
#include "config.hpp"
|
||||||
#include "global.hpp"
|
|
||||||
#include "guide-stepper.hpp"
|
#include "guide-stepper.hpp"
|
||||||
#include "encoder.hpp"
|
#include "encoder.hpp"
|
||||||
#include "shutdown.hpp"
|
#include "gpio_evaluateSwitch.hpp"
|
||||||
|
|
||||||
|
|
||||||
//macro to get smaller value out of two
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
|
|
||||||
//---------------------
|
//---------------------
|
||||||
//--- configuration ---
|
//--- configuration ---
|
||||||
//---------------------
|
//---------------------
|
||||||
//also see config.h
|
//also see config.hpp
|
||||||
//for pin definition
|
//for pin definition
|
||||||
|
|
||||||
#define STEPPER_TEST_TRAVEL 65 // mm
|
#define STEPPER_TEST_TRAVEL 65 //mm
|
||||||
|
//
|
||||||
#define MIN_MM 0 //TODO add feature so guide stays at zero for some steps (negative MIN_MM?), currently seems appropriate for even winding
|
#define MIN_MM 0
|
||||||
#define MAX_MM 95 //actual reel is 110, but currently guide turned out to stay at max position for too long
|
#define MAX_MM 110 //60
|
||||||
#define POS_MAX_STEPS MAX_MM * STEPPER_STEPS_PER_MM
|
#define POS_MAX_STEPS MAX_MM * STEPPER_STEPS_PER_MM
|
||||||
#define POS_MIN_STEPS MIN_MM * STEPPER_STEPS_PER_MM
|
#define POS_MIN_STEPS MIN_MM * STEPPER_STEPS_PER_MM
|
||||||
|
|
||||||
//tolerance added to last stored position at previous shutdown.
|
|
||||||
//When calibrating at startup the stepper moves for that sum to get track of zero position (ensure crashes into hardware limit for at least some time)
|
|
||||||
#define AUTO_HOME_TRAVEL_ADD_TO_LAST_POS_MM 20
|
|
||||||
#define MAX_TOTAL_AXIS_TRAVEL_MM 103 //max possible travel distance, needed for auto-home
|
|
||||||
|
|
||||||
// speeds for testing with potentiometer (test task only)
|
#define SPEED_MIN 2.0 //mm/s
|
||||||
#define SPEED_MIN 2.0 // mm/s
|
#define SPEED_MAX 60.0 //mm/s
|
||||||
#define SPEED_MAX 70.0 // mm/s
|
|
||||||
//note: actual speed is currently defined in config.h with STEPPER_SPEED_DEFAULT
|
#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 LAYER_THICKNESS_MM 5 //height of one cable layer on reel -> increase in radius
|
|
||||||
#define D_CABLE 6
|
#define D_CABLE 6
|
||||||
#define D_REEL 160
|
#define D_REEL 160 //actual 170
|
||||||
#define PI 3.14159
|
#define PI 3.14159
|
||||||
|
|
||||||
|
|
||||||
//simulate encoder with reset button to test stepper ctl task
|
|
||||||
//note STEPPER_TEST has to be defined as well
|
|
||||||
//#define STEPPER_SIMULATE_ENCODER
|
|
||||||
|
|
||||||
//----------------------
|
//----------------------
|
||||||
//----- variables ------
|
//----- variables ------
|
||||||
//----------------------
|
//----------------------
|
||||||
typedef enum axisDirection_t {AXIS_MOVING_LEFT = 0, AXIS_MOVING_RIGHT} axisDirection_t;
|
static DendoStepper step;
|
||||||
|
static const char *TAG = "stepper"; //tag for logging
|
||||||
|
|
||||||
static const char *TAG = "stepper-ctrl"; //tag for logging
|
static bool stepp_direction = true;
|
||||||
|
static bool dir = true, dirPrev; //TODO local variables in travelSteps?
|
||||||
static axisDirection_t currentAxisDirection = AXIS_MOVING_RIGHT;
|
|
||||||
static uint32_t posNow = 0;
|
static uint32_t posNow = 0;
|
||||||
|
|
||||||
static int layerCount = 0;
|
|
||||||
|
|
||||||
// queue for sending commands to task handling guide movement
|
|
||||||
static QueueHandle_t queue_commandsGuideTask;
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------
|
//----------------------
|
||||||
//----- functions ------
|
//----- functions ------
|
||||||
//----------------------
|
//----------------------
|
||||||
|
|
||||||
//=============================
|
|
||||||
//=== guide_getAxisPosSteps ===
|
|
||||||
//=============================
|
|
||||||
// return local variable posNow
|
|
||||||
// needed at shutdown detection to store last axis position in nvs
|
|
||||||
int guide_getAxisPosSteps(){
|
|
||||||
return posNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//==========================
|
|
||||||
//==== guide_moveToZero ====
|
|
||||||
//==========================
|
|
||||||
//tell stepper-control task to move cable guide to zero position
|
|
||||||
void guide_moveToZero(){
|
|
||||||
bool valueToSend = true; // or false
|
|
||||||
xQueueSend(queue_commandsGuideTask, &valueToSend, portMAX_DELAY);
|
|
||||||
ESP_LOGI(TAG, "sending command to stepper_ctl task via queue");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------
|
|
||||||
//---- travelSteps ----
|
|
||||||
//---------------------
|
|
||||||
//move axis certain Steps (relative) between left and right or reverse when negative
|
//move axis certain Steps (relative) between left and right or reverse when negative
|
||||||
void travelSteps(int stepsTarget){
|
void travelSteps(int stepsTarget){
|
||||||
//TODO simplify this function, one simple calculation of new position?
|
//posNow = step.getPositionMm(); //not otherwise controlled, so no update necessary
|
||||||
//with new custom driver no need to detect direction change
|
|
||||||
|
|
||||||
int stepsToGo, remaining;
|
int stepsToGo, remaining;
|
||||||
|
|
||||||
stepsToGo = abs(stepsTarget);
|
stepsToGo = abs(stepsTarget);
|
||||||
|
if(stepsTarget < 0) stepp_direction = !stepp_direction; //invert direction in reverse mode
|
||||||
|
|
||||||
// invert direction in reverse mode (cable gets spooled off reel)
|
|
||||||
if (stepsTarget < 0) {
|
|
||||||
currentAxisDirection = (currentAxisDirection == AXIS_MOVING_LEFT) ? AXIS_MOVING_RIGHT : AXIS_MOVING_LEFT; //toggle between RIGHT<->Left
|
|
||||||
}
|
|
||||||
|
|
||||||
while (stepsToGo != 0){
|
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 ---
|
//--- currently moving right ---
|
||||||
if (currentAxisDirection == AXIS_MOVING_RIGHT){ //currently moving right
|
if (stepp_direction == true){ //currently moving right
|
||||||
remaining = POS_MAX_STEPS - posNow; //calc remaining distance fom current position to limit
|
remaining = POS_MAX_STEPS - posNow; //calc remaining distance fom current position to limit
|
||||||
if (stepsToGo > remaining){ //new distance will exceed limit
|
if (stepsToGo > remaining){ //new distance will exceed limit
|
||||||
stepper_setTargetPosSteps(POS_MAX_STEPS); //move to limit
|
step.runAbs (POS_MAX_STEPS); //move to limit
|
||||||
stepper_waitForStop(1000);
|
dirPrev = dir;
|
||||||
|
dir = 1;
|
||||||
|
//while(step.getState() != 1) vTaskDelay(1); //wait for move to finish
|
||||||
posNow = POS_MAX_STEPS;
|
posNow = POS_MAX_STEPS;
|
||||||
currentAxisDirection = AXIS_MOVING_LEFT; //change current direction for next iteration
|
stepp_direction = false; //change current direction for next iteration
|
||||||
//increment/decrement layer count depending on current cable direction
|
|
||||||
layerCount += (stepsTarget > 0) - (stepsTarget < 0);
|
|
||||||
if (layerCount < 0) layerCount = 0; //negative layers are not possible
|
|
||||||
stepsToGo = stepsToGo - remaining; //decrease target length by already traveled distance
|
stepsToGo = stepsToGo - remaining; //decrease target length by already traveled distance
|
||||||
ESP_LOGI(TAG, " --- moved to max -> change direction (L) --- \n ");
|
ESP_LOGI(TAG, " --- moved to max -> change direction (L) --- \n ");
|
||||||
}
|
}
|
||||||
else { //target distance does not reach the limit
|
else { //target distance does not reach the limit
|
||||||
stepper_setTargetPosSteps(posNow + stepsToGo); //move by (remaining) distance to reach target length
|
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);
|
ESP_LOGD(TAG, "moving to %d\n", posNow+stepsToGo);
|
||||||
posNow += stepsToGo;
|
posNow += stepsToGo;
|
||||||
stepsToGo = 0; //finished, reset target length (could as well exit loop/break)
|
stepsToGo = 0; //finished, reset target length (could as well exit loop/break)
|
||||||
@@ -134,82 +103,107 @@ void travelSteps(int stepsTarget){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--- currently moving left ---
|
//--- currently moving left ---
|
||||||
else if (currentAxisDirection == AXIS_MOVING_LEFT){
|
else {
|
||||||
remaining = posNow - POS_MIN_STEPS;
|
remaining = posNow - POS_MIN_STEPS;
|
||||||
if (stepsToGo > remaining){
|
if (stepsToGo > remaining){
|
||||||
stepper_setTargetPosSteps(POS_MIN_STEPS);
|
step.runAbs (POS_MIN_STEPS);
|
||||||
stepper_waitForStop(1000);
|
dirPrev = dir;
|
||||||
|
dir = 0;
|
||||||
|
//while(step.getState() != 1) vTaskDelay(2); //wait for move to finish
|
||||||
posNow = POS_MIN_STEPS;
|
posNow = POS_MIN_STEPS;
|
||||||
currentAxisDirection = AXIS_MOVING_RIGHT; //switch direction
|
stepp_direction = true;
|
||||||
//increment/decrement layer count depending on current cable direction
|
|
||||||
layerCount += (stepsTarget > 0) - (stepsTarget < 0);
|
|
||||||
if (layerCount < 0) layerCount = 0; //negative layers are not possible
|
|
||||||
stepsToGo = stepsToGo - remaining;
|
stepsToGo = stepsToGo - remaining;
|
||||||
ESP_LOGI(TAG, " --- moved to min -> change direction (R) --- \n ");
|
ESP_LOGI(TAG, " --- moved to min -> change direction (R) --- \n ");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
stepper_setTargetPosSteps(posNow - stepsToGo); //when moving left the coordinate has to be decreased
|
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);
|
ESP_LOGD(TAG, "moving to %d\n", posNow - stepsToGo);
|
||||||
posNow -= stepsToGo;
|
posNow -= stepsToGo;
|
||||||
stepsToGo = 0;
|
stepsToGo = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(stepsTarget < 0) stepp_direction = !stepp_direction; //undo inversion of stepp_direction after reverse mode is finished
|
||||||
// undo inversion of currentAxisDirection after reverse mode is finished
|
|
||||||
if (stepsTarget < 0) {
|
|
||||||
currentAxisDirection = (currentAxisDirection == AXIS_MOVING_LEFT) ? AXIS_MOVING_RIGHT : AXIS_MOVING_LEFT; //toggle between RIGHT<->Left
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------
|
|
||||||
//---- travelMm ----
|
|
||||||
//------------------
|
|
||||||
//move axis certain Mm (relative) between left and right or reverse when negative
|
//move axis certain Mm (relative) between left and right or reverse when negative
|
||||||
void travelMm(int length){
|
void travelMm(int length){
|
||||||
travelSteps(length * STEPPER_STEPS_PER_MM);
|
travelSteps(length * STEPPER_STEPS_PER_MM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//----------------------
|
//define zero/start position
|
||||||
//---- init_stepper ----
|
//currently crashes into hardware limitation for certain time
|
||||||
//----------------------
|
//TODO: limit switch
|
||||||
//initialize/configure stepper instance
|
void home() {
|
||||||
void init_stepper() {
|
ESP_LOGW(TAG, "auto-home...");
|
||||||
//TODO unnecessary wrapper?
|
step.setSpeedMm(100, 500, 10);
|
||||||
ESP_LOGW(TAG, "initializing stepper...");
|
step.runInf(1);
|
||||||
stepper_init();
|
vTaskDelay(1500 / portTICK_PERIOD_MS);
|
||||||
// create queue for sending commands to task handling guide movement
|
step.stop();
|
||||||
// currently length 1 and only one command possible, thus bool
|
step.resetAbsolute();
|
||||||
queue_commandsGuideTask = xQueueCreate(1, sizeof(bool));
|
ESP_LOGW(TAG, "auto-home finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------
|
//initialize/configure stepper instance
|
||||||
//--- updateSpeedFromAdc ---
|
void init_stepper() {
|
||||||
//--------------------------
|
ESP_LOGW(TAG, "initializing stepper...");
|
||||||
//function that updates speed value using ADC input and configured MIN/MAX - used for testing only
|
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() {
|
void updateSpeedFromAdc() {
|
||||||
int potiRead = gpio_readAdc(ADC_CHANNEL_POTI); //0-4095 GPIO34
|
int potiRead = gpio_readAdc(ADC_CHANNEL_POTI); //0-4095 GPIO34
|
||||||
double poti = potiRead/4095.0;
|
double poti = potiRead/4095.0;
|
||||||
int speed = poti*(SPEED_MAX-SPEED_MIN) + SPEED_MIN;
|
int speed = poti*(SPEED_MAX-SPEED_MIN) + SPEED_MIN;
|
||||||
stepper_setSpeed(speed);
|
step.setSpeedMm(speed, ACCEL_MS, DECEL_MS);
|
||||||
ESP_LOGW(TAG, "poti: %d (%.2lf%%), set speed to: %d", potiRead, poti*100, speed);
|
ESP_LOGW(TAG, "poti: %d (%.2lf%%), set speed to: %d", potiRead, poti*100, speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================
|
//----------------------------
|
||||||
//==== TASK stepper_test =====
|
//---- TASK stepper-test -----
|
||||||
//============================
|
//----------------------------
|
||||||
//test axis without using encoder input
|
|
||||||
#ifndef STEPPER_SIMULATE_ENCODER
|
|
||||||
void task_stepper_test(void *pvParameter)
|
void task_stepper_test(void *pvParameter)
|
||||||
{
|
{
|
||||||
stepper_init();
|
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){
|
while(1){
|
||||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
@@ -224,167 +218,90 @@ void task_stepper_test(void *pvParameter)
|
|||||||
SW_CUT.handle();
|
SW_CUT.handle();
|
||||||
SW_AUTO_CUT.handle();
|
SW_AUTO_CUT.handle();
|
||||||
|
|
||||||
#ifdef ONE_BUTTON_TEST //test with "reset-button" only
|
|
||||||
static int state = 0;
|
|
||||||
//cycle through test commands with one button
|
|
||||||
if (SW_RESET.risingEdge) {
|
if (SW_RESET.risingEdge) {
|
||||||
switch (state){
|
ESP_LOGI(TAG, "button - stop stepper\n ");
|
||||||
case 0:
|
buzzer.beep(1, 1000, 100);
|
||||||
stepper_setTargetPosMm(50);
|
step.stop();
|
||||||
//stepper_setTargetPosSteps(1000);
|
|
||||||
state++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
stepper_setTargetPosMm(80);
|
|
||||||
//stepper_setTargetPosSteps(100);
|
|
||||||
state++;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
stepper_setTargetPosMm(20);
|
|
||||||
//stepper_setTargetPosSteps(100);
|
|
||||||
state++;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
stepper_setTargetPosMm(60);
|
|
||||||
//stepper_setTargetPosSteps(2000);
|
|
||||||
state = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else //test with all buttons
|
|
||||||
if (SW_RESET.risingEdge) {
|
|
||||||
buzzer.beep(1, 500, 100);
|
|
||||||
stepper_setTargetPosMm(0);
|
|
||||||
}
|
}
|
||||||
if (SW_PRESET1.risingEdge) {
|
if (SW_PRESET1.risingEdge) {
|
||||||
buzzer.beep(1, 200, 100);
|
ESP_LOGI(TAG, "button - moving right\n ");
|
||||||
stepper_setTargetPosMm(50);
|
buzzer.beep(2, 300, 100);
|
||||||
}
|
step.setSpeedMm(SPEED, ACCEL_MS, DECEL_MS);
|
||||||
if (SW_PRESET2.risingEdge) {
|
step.runPosMm(15);
|
||||||
buzzer.beep(2, 200, 100);
|
|
||||||
stepper_setTargetPosMm(75);
|
|
||||||
}
|
}
|
||||||
if (SW_PRESET3.risingEdge) {
|
if (SW_PRESET3.risingEdge) {
|
||||||
buzzer.beep(3, 200, 100);
|
ESP_LOGI(TAG, "button - moving left\n ");
|
||||||
stepper_setTargetPosMm(100);
|
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());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //end SIMULATE_ENCODER
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================
|
//----------------------------
|
||||||
//===== TASK stepper_ctl =====
|
//----- TASK stepper-ctl -----
|
||||||
//============================
|
//----------------------------
|
||||||
//task controlling the linear axis guiding the cable according to wire length spooled
|
|
||||||
#ifdef STEPPER_SIMULATE_ENCODER
|
|
||||||
void task_stepper_test(void *pvParameter)
|
|
||||||
#else
|
|
||||||
void task_stepper_ctl(void *pvParameter)
|
void task_stepper_ctl(void *pvParameter)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
//-- variables --
|
//variables
|
||||||
static int encStepsPrev = 0; //measured encoder steps at last run
|
int encStepsNow = 0; //get curret steps of encoder
|
||||||
static double travelStepsPartial = 0; //store resulted remaining partial steps last run
|
int encStepsPrev = 0; //steps at last check
|
||||||
|
int encStepsDelta = 0; //steps changed since last iteration
|
||||||
//temporary variables for calculating required steps, or logging
|
|
||||||
int encStepsNow = 0; //get curretly measured steps of encoder
|
|
||||||
int encStepsDelta = 0; //encoder steps changed since last iteration
|
|
||||||
|
|
||||||
double cableLen = 0;
|
double cableLen = 0;
|
||||||
double travelStepsExact = 0; //steps axis has to travel
|
double travelStepsExact = 0; //steps axis has to travel
|
||||||
|
double travelStepsPartial = 0;
|
||||||
int travelStepsFull = 0;
|
int travelStepsFull = 0;
|
||||||
double travelMm = 0;
|
double travelMm = 0;
|
||||||
double turns = 0;
|
double turns = 0;
|
||||||
float currentDiameter;
|
|
||||||
|
|
||||||
|
float potiModifier;
|
||||||
|
|
||||||
|
|
||||||
//initialize stepper at task start
|
|
||||||
init_stepper();
|
init_stepper();
|
||||||
//define zero-position
|
home();
|
||||||
// use last known position stored at last shutdown to reduce time crashing into hardware limit
|
|
||||||
int posLastShutdown = nvsReadLastAxisPosSteps();
|
|
||||||
if (posLastShutdown >= 0)
|
|
||||||
{ // would be -1 when failed
|
|
||||||
ESP_LOGW(TAG, "auto-home: considerting pos last shutdown %dmm + tolerance %dmm",
|
|
||||||
posLastShutdown / STEPPER_STEPS_PER_MM,
|
|
||||||
AUTO_HOME_TRAVEL_ADD_TO_LAST_POS_MM);
|
|
||||||
// home considering last position and offset, but limit to max distance possible
|
|
||||||
stepper_home(MIN((posLastShutdown/STEPPER_STEPS_PER_MM + AUTO_HOME_TRAVEL_ADD_TO_LAST_POS_MM), MAX_TOTAL_AXIS_TRAVEL_MM));
|
|
||||||
}
|
|
||||||
else { // default to max travel when read from nvs failed
|
|
||||||
stepper_home(MAX_TOTAL_AXIS_TRAVEL_MM);
|
|
||||||
}
|
|
||||||
|
|
||||||
//repeatedly read changes in measured cable length and move axis accordingly
|
|
||||||
while(1){
|
while(1){
|
||||||
#ifdef STEPPER_SIMULATE_ENCODER
|
|
||||||
//TESTING - simulate encoder using switch
|
|
||||||
SW_RESET.handle();
|
|
||||||
//note
|
|
||||||
if (SW_RESET.risingEdge) encStepsNow += 500;
|
|
||||||
#else
|
|
||||||
//get current length
|
//get current length
|
||||||
encStepsNow = encoder_getSteps();
|
encStepsNow = encoder_getSteps();
|
||||||
#endif
|
|
||||||
|
|
||||||
// move to zero and reset if command received via queue
|
|
||||||
bool receivedValue;
|
|
||||||
if (xQueueReceive(queue_commandsGuideTask, &receivedValue, 0) == pdTRUE)
|
|
||||||
{
|
|
||||||
// Process the received value
|
|
||||||
// TODO support other commands (currently only move to zero possible)
|
|
||||||
ESP_LOGW(TAG, "task: move-to-zero command received via queue, starting move, waiting until position reached");
|
|
||||||
stepper_setTargetPosMm(0);
|
|
||||||
stepper_waitForStop();
|
|
||||||
//reset variables -> start tracking cable movement starting from position zero
|
|
||||||
// ensure stepsDelta is 0
|
|
||||||
encStepsNow = encoder_getSteps();
|
|
||||||
encStepsPrev = encStepsNow;
|
|
||||||
travelStepsPartial = 0;
|
|
||||||
// set locally stored axis position and counted layers to 0 (used for calculating the target axis coordinate and steps)
|
|
||||||
posNow = 0;
|
|
||||||
layerCount = 0;
|
|
||||||
currentAxisDirection = AXIS_MOVING_RIGHT;
|
|
||||||
ESP_LOGW(TAG, "at position 0, reset variables, resuming normal cable guiding operation");
|
|
||||||
}
|
|
||||||
|
|
||||||
//calculate change
|
//calculate change
|
||||||
encStepsDelta = encStepsNow - encStepsPrev;
|
encStepsDelta = encStepsNow - encStepsPrev; //FIXME MAJOR BUG: when resetting encoder/length in control task, diff will be huge!
|
||||||
//check if reset happend without moving to zero before - resulting in huge diff
|
|
||||||
if (encStepsDelta != 0 && encStepsNow == 0){ // this should not happen and causes weird movement
|
|
||||||
ESP_LOGE(TAG, "encoder steps changed to 0 (reset) without previous moveToZero() call, resulting in stepsDelta=%d", encStepsDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
//read potentiometer and normalize (0-1) to get a variable for testing
|
//read potentiometer and normalize (0-1) to get a variable for testing
|
||||||
//float potiModifier = (float) gpio_readAdc(ADC_CHANNEL_POTI) / 4095; //0-4095 -> 0-1
|
potiModifier = (float) gpio_readAdc(ADC_CHANNEL_POTI) / 4095; //0-4095 -> 0-1
|
||||||
//ESP_LOGI(TAG, "current poti-modifier = %f", potiModifier);
|
//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
|
//calculate steps to move
|
||||||
cableLen = (double)encStepsDelta * 1000 / ENCODER_STEPS_PER_METER;
|
cableLen = (double)encStepsDelta * 1000 / ENCODER_STEPS_PER_METER;
|
||||||
//effective diameter increases each layer
|
turns = cableLen / (PI * D_REEL);
|
||||||
currentDiameter = D_REEL + LAYER_THICKNESS_MM * 2 * layerCount;
|
|
||||||
turns = cableLen / (PI * currentDiameter);
|
|
||||||
travelMm = turns * D_CABLE;
|
travelMm = turns * D_CABLE;
|
||||||
travelStepsExact = travelMm * STEPPER_STEPS_PER_MM + travelStepsPartial; //convert mm to steps and add not moved partial steps
|
travelStepsExact = travelMm * STEPPER_STEPS_PER_MM + travelStepsPartial; //convert mm to steps and add not moved partial steps
|
||||||
travelStepsPartial = 0;
|
travelStepsPartial = 0;
|
||||||
travelStepsFull = (int)travelStepsExact;
|
travelStepsFull = (int)travelStepsExact;
|
||||||
|
|
||||||
//move axis when ready to move at least 1 full step
|
//move axis when ready to move at least 1 step
|
||||||
if (abs(travelStepsFull) > 1){
|
if (abs(travelStepsFull) > 1){
|
||||||
travelStepsPartial = fmod(travelStepsExact, 1); //save remaining partial steps to be added in the next iteration
|
travelStepsPartial = fmod(travelStepsExact, 1); //save remaining partial steps to be added in the next iteration
|
||||||
ESP_LOGI(TAG, "dCablelen=%.2lf, dTurns=%.2lf, travelMm=%.3lf, StepsExact: %.3lf, StepsFull=%d, StepsPartial=%.3lf, totalLayerCount=%d, diameter=%.1f", cableLen, turns, travelMm, travelStepsExact, travelStepsFull, travelStepsPartial, layerCount, currentDiameter);
|
ESP_LOGD(TAG, "cablelen=%.2lf, turns=%.2lf, travelMm=%.3lf, travelStepsExact: %.3lf, travelStepsFull=%d, partialStep=%.3lf", cableLen, turns, travelMm, travelStepsExact, travelStepsFull, travelStepsPartial);
|
||||||
ESP_LOGD(TAG, "MOVING %d steps", travelStepsFull);
|
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);
|
travelSteps(travelStepsExact);
|
||||||
encStepsPrev = encStepsNow; //update previous length
|
encStepsPrev = encStepsNow; //update previous length
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//TODO use encoder queue to only run this check at encoder event?
|
//TODO use encoder queue to only run this check at encoder event?
|
||||||
vTaskDelay(5);
|
vTaskDelay(2);
|
||||||
}
|
}
|
||||||
vTaskDelay(5 / portTICK_PERIOD_MS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,3 @@ void task_stepper_test(void *pvParameter);
|
|||||||
//task that initializes and controls the stepper motor
|
//task that initializes and controls the stepper motor
|
||||||
// - moves stepper according to encoder movement
|
// - moves stepper according to encoder movement
|
||||||
void task_stepper_ctl(void *pvParameter);
|
void task_stepper_ctl(void *pvParameter);
|
||||||
|
|
||||||
|
|
||||||
//tell stepper-control task to move cable guide to zero position
|
|
||||||
void guide_moveToZero();
|
|
||||||
|
|
||||||
// return local variable posNow that stores the current position of cable guide axis in steps
|
|
||||||
// needed by shutdown to store last axis position in nvs
|
|
||||||
int guide_getAxisPosSteps();
|
|
||||||
@@ -8,38 +8,28 @@ extern "C"
|
|||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "driver/adc.h"
|
#include "driver/adc.h"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.hpp"
|
||||||
#include "global.hpp"
|
|
||||||
#include "control.hpp"
|
#include "control.hpp"
|
||||||
#include "buzzer.hpp"
|
#include "buzzer.hpp"
|
||||||
#include "switchesAnalog.hpp"
|
#include "switchesAnalog.hpp"
|
||||||
#include "guide-stepper.hpp"
|
#include "guide-stepper.hpp"
|
||||||
#include "encoder.hpp"
|
#include "encoder.hpp"
|
||||||
#include "shutdown.hpp"
|
|
||||||
|
|
||||||
#include "stepper.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
//=================================
|
//=================================
|
||||||
//=========== functions ===========
|
//=========== functions ===========
|
||||||
//=================================
|
//=================================
|
||||||
|
|
||||||
//------------------------
|
|
||||||
//--- configure output ---
|
//--- configure output ---
|
||||||
//------------------------
|
//function to configure gpio pin as output
|
||||||
//configure a 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 ---
|
||||||
//---- init gpios ----
|
|
||||||
//--------------------
|
|
||||||
void init_gpios(){
|
void init_gpios(){
|
||||||
//--- outputs ---
|
//--- outputs ---
|
||||||
//4x stepper mosfets
|
//4x stepper mosfets
|
||||||
@@ -61,8 +51,6 @@ void init_gpios(){
|
|||||||
//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
|
||||||
|
|
||||||
adc1_config_channel_atten(ADC_CHANNEL_SUPPLY_VOLTAGE, ADC_ATTEN_DB_11); //max voltage
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -84,41 +72,33 @@ void task_buzzer( void * pvParameters ){
|
|||||||
//======================================
|
//======================================
|
||||||
extern "C" void app_main()
|
extern "C" void app_main()
|
||||||
{
|
{
|
||||||
//init outputs and adc
|
//init outputs
|
||||||
init_gpios();
|
init_gpios();
|
||||||
|
|
||||||
//enable 5V volage regulator (needed for display)
|
//enable 5V volate regulator
|
||||||
gpio_set_level(GPIO_NUM_17, 1);
|
gpio_set_level(GPIO_NUM_17, 1);
|
||||||
|
|
||||||
//init encoder (global)
|
//init encoder (global)
|
||||||
encoder_queue = encoder_init();
|
encoder_queue = encoder_init();
|
||||||
|
|
||||||
//define loglevel
|
//define loglevel
|
||||||
esp_log_level_set("*", ESP_LOG_INFO); //default loglevel
|
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("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-driver", ESP_LOG_WARN);
|
esp_log_level_set("stepper", ESP_LOG_DEBUG);
|
||||||
esp_log_level_set("stepper-ctrl", ESP_LOG_WARN);
|
esp_log_level_set("DendoStepper", ESP_LOG_DEBUG); //stepper lib
|
||||||
esp_log_level_set("Dendostepper", ESP_LOG_WARN); //stepper lib
|
|
||||||
esp_log_level_set("calc", ESP_LOG_WARN); //stepper lib
|
esp_log_level_set("calc", ESP_LOG_WARN); //stepper lib
|
||||||
esp_log_level_set("lowVoltage", ESP_LOG_INFO);
|
|
||||||
|
|
||||||
#ifdef STEPPER_TEST
|
#ifdef STEPPER_TEST
|
||||||
//create task for testing the stepper motor
|
//create task for stepper testing
|
||||||
xTaskCreate(task_stepper_test, "task_stepper_test", configMINIMAL_STACK_SIZE * 3, NULL, 2, NULL);
|
xTaskCreate(task_stepper_test, "task_stepper_test", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
|
||||||
//xTaskCreate(task_stepper_debug, "task_stepper_test", configMINIMAL_STACK_SIZE * 3, NULL, 2, NULL);
|
|
||||||
#else
|
#else
|
||||||
//create task for detecting power-off
|
//create task for controlling the machine
|
||||||
xTaskCreate(&task_shutDownDetection, "task_shutdownDet", 2048, NULL, 2, NULL);
|
xTaskCreate(task_control, "task_control", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
|
||||||
// wait for nvs to be initialized in shutDownDetection task
|
|
||||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
//create task for controlling the machine
|
//create task for controlling the machine
|
||||||
xTaskCreate(task_control, "task_control", configMINIMAL_STACK_SIZE * 3, NULL, 4, NULL);
|
xTaskCreate(task_stepper_ctl, "task_stepper_ctl", configMINIMAL_STACK_SIZE * 5, NULL, 5, NULL);
|
||||||
|
|
||||||
//create task for controlling the stepper motor (linear axis that guids the cable)
|
|
||||||
xTaskCreate(task_stepper_ctl, "task_stepper_ctl", configMINIMAL_STACK_SIZE * 3, NULL, 2, NULL);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//create task for handling the buzzer
|
//create task for handling the buzzer
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
extern "C"
|
|
||||||
{
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <freertos/task.h>
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "driver/adc.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "nvs.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "shutdown.hpp"
|
|
||||||
|
|
||||||
#include "guide-stepper.hpp"
|
|
||||||
|
|
||||||
#define ADC_LOW_VOLTAGE_THRESHOLD 3200 // adc value where shut down is detected (store certain values before complete power loss)
|
|
||||||
|
|
||||||
static const char *TAG = "lowVoltage"; // tag for logging
|
|
||||||
nvs_handle_t nvsHandle; // access nvs that was opened once, in any function
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// store a u32 value in nvs as "lastPosSteps"
|
|
||||||
void nvsWriteLastAxisPos(uint32_t value)
|
|
||||||
{
|
|
||||||
// update nvs value
|
|
||||||
esp_err_t err = nvs_set_u32(nvsHandle, "lastPosSteps", value);
|
|
||||||
if (err != ESP_OK)
|
|
||||||
ESP_LOGE(TAG, "nvs: failed writing");
|
|
||||||
err = nvs_commit(nvsHandle);
|
|
||||||
if (err != ESP_OK)
|
|
||||||
ESP_LOGE(TAG, "nvs: failed committing updates");
|
|
||||||
else
|
|
||||||
ESP_LOGI(TAG, "nvs: successfully committed updates");
|
|
||||||
ESP_LOGW(TAG, "updated value in nvs to %d", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// read "lastPosSteps" from nvs, returns -1 if failed
|
|
||||||
int nvsReadLastAxisPosSteps()
|
|
||||||
{
|
|
||||||
uint32_t valueRead;
|
|
||||||
esp_err_t err = nvs_get_u32(nvsHandle, "lastPosSteps", &valueRead);
|
|
||||||
switch (err)
|
|
||||||
{
|
|
||||||
case ESP_OK:
|
|
||||||
ESP_LOGW(TAG, "Successfully read value %d from nvs", valueRead);
|
|
||||||
return valueRead;
|
|
||||||
break;
|
|
||||||
case ESP_ERR_NVS_NOT_FOUND:
|
|
||||||
ESP_LOGE(TAG, "nvs: the value '%s' is not initialized yet", "lastPosSteps");
|
|
||||||
return -1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGE(TAG, "Error (%s) reading nvs!", esp_err_to_name(err));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// task that repeatedly checks supply voltage (12V) and saves certain values to nvs in case of power off detected
|
|
||||||
// note: with the 2200uF capacitor in the 12V supply and measuring if 12V start do drop here, there is more than enough time to take action until the 3v3 regulator turns off
|
|
||||||
void task_shutDownDetection(void *pvParameter)
|
|
||||||
{
|
|
||||||
//--- Initialize NVS ---
|
|
||||||
ESP_LOGW(TAG, "initializing nvs...");
|
|
||||||
esp_err_t err = nvs_flash_init();
|
|
||||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "NVS truncated -> deleting flash");
|
|
||||||
// Retry nvs_flash_init
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
||||||
err = nvs_flash_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
//--- open nvs-flash ---
|
|
||||||
ESP_LOGW(TAG, "opening NVS-handle...");
|
|
||||||
// create handle available for all functions in this file
|
|
||||||
err = nvs_open("storage", NVS_READWRITE, &nvsHandle);
|
|
||||||
if (err != ESP_OK)
|
|
||||||
ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err));
|
|
||||||
|
|
||||||
// read stored value (returns 0 if unitialized/failed)
|
|
||||||
//int lastPosSteps = nvsReadLastAxisPosSteps();
|
|
||||||
//ESP_LOGW(TAG, "=> read value %d from nvs (stored at last shutdown)", lastPosSteps);
|
|
||||||
|
|
||||||
// repeatedly read ADC and check if below low voltage threshold
|
|
||||||
bool voltageBelowThreshold = false;
|
|
||||||
while (1) //TODO limit save frequency in case voltage repeadedly varys between threshold for some reason (e.g. offset drift)
|
|
||||||
{
|
|
||||||
// read adc
|
|
||||||
int adc_reading = adc1_get_raw(ADC_CHANNEL_SUPPLY_VOLTAGE);
|
|
||||||
|
|
||||||
// evaulate threshold
|
|
||||||
if (adc_reading < ADC_LOW_VOLTAGE_THRESHOLD) // below threshold => POWER SHUTDOWN DETECTED
|
|
||||||
{
|
|
||||||
// write to nvs and log once at change to below
|
|
||||||
if (!voltageBelowThreshold){
|
|
||||||
nvsWriteLastAxisPos(guide_getAxisPosSteps());
|
|
||||||
ESP_LOGE(TAG, "voltage now below threshold! now=%d threshold=%d -> wrote last axis-pos to nvs", adc_reading, ADC_LOW_VOLTAGE_THRESHOLD);
|
|
||||||
voltageBelowThreshold = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (voltageBelowThreshold) // above threshold and previously below
|
|
||||||
{
|
|
||||||
// log at change to above
|
|
||||||
ESP_LOGE(TAG, "voltage above threshold again: %d > %d - issue with power supply, or too threshold too high?", adc_reading, ADC_LOW_VOLTAGE_THRESHOLD);
|
|
||||||
voltageBelowThreshold = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// always log for debugging/calibrating
|
|
||||||
ESP_LOGD(TAG, "read adc battery voltage: %d", adc_reading);
|
|
||||||
|
|
||||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
// task that repeatedly checks supply voltage (12V) and saves certain values to nvs in case of it drops below a certain threshold (power off detected)
|
|
||||||
void task_shutDownDetection(void *pvParameter);
|
|
||||||
|
|
||||||
// read last axis position in steps from nvs
|
|
||||||
// returns -1 when reading from nvs failed
|
|
||||||
int nvsReadLastAxisPosSteps();
|
|
||||||
304
main/stepper.cpp
304
main/stepper.cpp
@@ -1,304 +0,0 @@
|
|||||||
//custom driver for stepper motor
|
|
||||||
#include "config.h"
|
|
||||||
#include "global.hpp"
|
|
||||||
#include "hal/timer_types.h"
|
|
||||||
#include <cstdint>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "driver/timer.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//=====================
|
|
||||||
//=== configuration ===
|
|
||||||
//=====================
|
|
||||||
//used macros from config.h:
|
|
||||||
//#define STEPPER_STEP_PIN GPIO_NUM_18 //mos1
|
|
||||||
//#define STEPPER_DIR_PIN GPIO_NUM_16 //ST3
|
|
||||||
|
|
||||||
//#define STEPPER_STEPS_PER_MM 200/2 //steps/mm (steps-per-rot / slope)
|
|
||||||
//#define STEPPER_SPEED_DEFAULT 20 //mm/s
|
|
||||||
//#define STEPPER_SPEED_MIN 4 //mm/s - speed threshold at which stepper immediately starts/stops
|
|
||||||
//#define STEPPER_ACCEL_INC 3 //steps/s increment per cycle
|
|
||||||
//#define STEPPER_DECEL_INC 8 //steps/s decrement per cycle
|
|
||||||
|
|
||||||
#define TIMER_F 1000000ULL
|
|
||||||
#define TICK_PER_S TIMER_S
|
|
||||||
#define NS_TO_T_TICKS(x) (x)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//========================
|
|
||||||
//=== global variables ===
|
|
||||||
//========================
|
|
||||||
static const char *TAG = "stepper-driver"; //tag for logging
|
|
||||||
|
|
||||||
bool direction = 1;
|
|
||||||
bool directionTarget = 1;
|
|
||||||
bool timerIsRunning = false;
|
|
||||||
bool timer_isr(void *arg);
|
|
||||||
|
|
||||||
static timer_group_t timerGroup = TIMER_GROUP_0;
|
|
||||||
static timer_idx_t timerIdx = TIMER_0;
|
|
||||||
|
|
||||||
//TODO the below variables can be moved to isr function once debug output is no longer needed
|
|
||||||
static uint64_t posTarget = 0;
|
|
||||||
static uint64_t posNow = 0;
|
|
||||||
static uint64_t stepsToGo = 0;
|
|
||||||
static uint32_t speedMin = STEPPER_SPEED_MIN * STEPPER_STEPS_PER_MM;
|
|
||||||
static uint32_t speedNow = speedMin;
|
|
||||||
static int debug = 0;
|
|
||||||
static uint32_t speedTarget = STEPPER_SPEED_DEFAULT * STEPPER_STEPS_PER_MM;
|
|
||||||
//TODO/NOTE increment actually has to be re-calculated every run to have linear accel (because also gets called faster/slower)
|
|
||||||
static uint32_t decel_increment = STEPPER_DECEL_INC;
|
|
||||||
static uint32_t accel_increment = STEPPER_ACCEL_INC;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//======================
|
|
||||||
//===== DEBUG task =====
|
|
||||||
//======================
|
|
||||||
void task_stepper_debug(void *pvParameter){
|
|
||||||
while (1){
|
|
||||||
ESP_LOGI("stepper-DEBUG",
|
|
||||||
"timer=%d "
|
|
||||||
"dir=%d "
|
|
||||||
"dirTarget=%d "
|
|
||||||
"posTarget=%llu "
|
|
||||||
"posNow=%llu "
|
|
||||||
"stepsToGo=%llu "
|
|
||||||
"speedNow=%u "
|
|
||||||
"speedTarget=%u "
|
|
||||||
"debug=%d ",
|
|
||||||
|
|
||||||
timerIsRunning,
|
|
||||||
direction,
|
|
||||||
directionTarget,
|
|
||||||
posTarget,
|
|
||||||
posNow,
|
|
||||||
stepsToGo,
|
|
||||||
speedNow,
|
|
||||||
speedTarget,
|
|
||||||
debug
|
|
||||||
);
|
|
||||||
|
|
||||||
vTaskDelay(300 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=====================
|
|
||||||
//===== set speed =====
|
|
||||||
//=====================
|
|
||||||
void stepper_setSpeed(uint32_t speedMmPerS) {
|
|
||||||
ESP_LOGI(TAG, "set target speed from %u to %u mm/s (%u steps/s)",
|
|
||||||
speedTarget, speedMmPerS, speedMmPerS * STEPPER_STEPS_PER_MM);
|
|
||||||
speedTarget = speedMmPerS * STEPPER_STEPS_PER_MM;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==========================
|
|
||||||
//== set target pos STEPS ==
|
|
||||||
//==========================
|
|
||||||
void stepper_setTargetPosSteps(uint64_t target_steps) {
|
|
||||||
ESP_LOGI(TAG, "update target position from %llu to %llu steps (stepsNow: %llu", posTarget, target_steps, posNow);
|
|
||||||
posTarget = target_steps;
|
|
||||||
|
|
||||||
// Check if the timer is currently paused
|
|
||||||
if (!timerIsRunning){
|
|
||||||
// If the timer is paused, start it again with the updated targetSteps
|
|
||||||
timerIsRunning = true;
|
|
||||||
ESP_LOGI(TAG, "starting timer");
|
|
||||||
ESP_ERROR_CHECK(timer_set_alarm_value(timerGroup, timerIdx, 1000));
|
|
||||||
//timer_set_counter_value(timerGroup, timerIdx, 1000);
|
|
||||||
ESP_ERROR_CHECK(timer_start(timerGroup, timerIdx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=========================
|
|
||||||
//=== set target pos MM ===
|
|
||||||
//=========================
|
|
||||||
void stepper_setTargetPosMm(uint32_t posMm){
|
|
||||||
ESP_LOGI(TAG, "set target position to %u mm", posMm);
|
|
||||||
stepper_setTargetPosSteps(posMm * STEPPER_STEPS_PER_MM);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//=======================
|
|
||||||
//===== waitForStop =====
|
|
||||||
//=======================
|
|
||||||
//delay until stepper is stopped, optional timeout in ms, 0 = no limit
|
|
||||||
void stepper_waitForStop(uint32_t timeoutMs){
|
|
||||||
ESP_LOGI(TAG, "waiting for stepper to stop...");
|
|
||||||
uint32_t timestampStart = esp_log_timestamp();
|
|
||||||
while (timerIsRunning) {
|
|
||||||
if ( (esp_log_timestamp() - timestampStart) >= timeoutMs && timeoutMs != 0){
|
|
||||||
ESP_LOGE(TAG, "timeout waiting for stepper to stop");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
ESP_LOGI(TAG, "finished waiting stepper to stop");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//======================
|
|
||||||
//======== home ========
|
|
||||||
//======================
|
|
||||||
//define zero/start position
|
|
||||||
//run to limit and define zero/start position.
|
|
||||||
//Currently simply runs stepper for travelMm and bumps into hardware limit
|
|
||||||
void stepper_home(uint32_t travelMm){
|
|
||||||
//TODO add timeout, limitswitch...
|
|
||||||
ESP_LOGW(TAG, "initiate auto-home, moving %d mm...", travelMm);
|
|
||||||
posNow = travelMm * STEPPER_STEPS_PER_MM;
|
|
||||||
while (posNow != 0){
|
|
||||||
//reactivate just in case stopped by other call to prevent deadlock
|
|
||||||
if (!timerIsRunning) {
|
|
||||||
stepper_setTargetPosSteps(0);
|
|
||||||
}
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
ESP_LOGW(TAG, "finished auto-home");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//========================
|
|
||||||
//===== init stepper =====
|
|
||||||
//========================
|
|
||||||
void stepper_init(){
|
|
||||||
ESP_LOGI(TAG, "init - configure struct...");
|
|
||||||
|
|
||||||
// Configure pulse and direction pins as outputs
|
|
||||||
ESP_LOGI(TAG, "init - configure gpio pins...");
|
|
||||||
gpio_set_direction(STEPPER_DIR_PIN, GPIO_MODE_OUTPUT);
|
|
||||||
gpio_set_direction(STEPPER_STEP_PIN, GPIO_MODE_OUTPUT);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "init - initialize/configure timer...");
|
|
||||||
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
|
|
||||||
};
|
|
||||||
ESP_ERROR_CHECK(timer_init(timerGroup, timerIdx, &timer_conf)); // init the timer
|
|
||||||
ESP_ERROR_CHECK(timer_set_counter_value(timerGroup, timerIdx, 0)); // set it to 0
|
|
||||||
ESP_ERROR_CHECK(timer_isr_callback_add(timerGroup, timerIdx, timer_isr, (void *)timerIdx, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================================
|
|
||||||
//=== timer interrupt function ===
|
|
||||||
//================================
|
|
||||||
bool timer_isr(void *arg) {
|
|
||||||
|
|
||||||
//-----------------
|
|
||||||
//--- variables ---
|
|
||||||
//-----------------
|
|
||||||
//TODO used (currently global) variables here
|
|
||||||
|
|
||||||
//-----------------------------------
|
|
||||||
//--- define direction, stepsToGo ---
|
|
||||||
//-----------------------------------
|
|
||||||
//Note: the idea is that the stepper has to decelerate to min speed first before changeing the direction
|
|
||||||
//define target direction depending on position difference
|
|
||||||
bool directionTarget = posTarget > posNow ? 1 : 0;
|
|
||||||
//DIRECTION DIFFERS (change)
|
|
||||||
if ( (direction != directionTarget) && (posTarget != posNow)) {
|
|
||||||
if (stepsToGo == 0){ //standstill
|
|
||||||
direction = directionTarget; //switch direction
|
|
||||||
gpio_set_level(STEPPER_DIR_PIN, direction);
|
|
||||||
stepsToGo = abs(int64_t(posTarget - posNow));
|
|
||||||
} else {
|
|
||||||
//set to minimun decel steps
|
|
||||||
stepsToGo = (speedNow - speedMin) / decel_increment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//NORMAL (any direction 0/1)
|
|
||||||
else {
|
|
||||||
stepsToGo = abs(int64_t(posTarget - posNow));
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
//--- define speed ---
|
|
||||||
//--------------------
|
|
||||||
//FIXME noticed crash: division by 0 when min speed > target speed
|
|
||||||
uint64_t stepsDecelRemaining = (speedNow - speedMin) / decel_increment;
|
|
||||||
//DECELERATE
|
|
||||||
|
|
||||||
//prevent hard stop (faster stop than decel ramp)
|
|
||||||
//Idea: when target gets lowered while decelerating,
|
|
||||||
// move further than target to not exceed decel ramp (overshoot),
|
|
||||||
// then change dir and move back to actual target pos
|
|
||||||
if (stepsToGo < stepsDecelRemaining/2){ //significantly less steps planned to comply with decel ramp
|
|
||||||
stepsToGo = stepsDecelRemaining; //set to required steps
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stepsToGo <= stepsDecelRemaining) {
|
|
||||||
if ((speedNow - speedMin) > decel_increment) {
|
|
||||||
speedNow -= decel_increment;
|
|
||||||
} else {
|
|
||||||
speedNow = speedMin; //PAUSE HERE??? / irrelevant?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//ACCELERATE
|
|
||||||
else if (speedNow < speedTarget) {
|
|
||||||
speedNow += accel_increment;
|
|
||||||
if (speedNow > speedTarget) speedNow = speedTarget;
|
|
||||||
}
|
|
||||||
//COASTING
|
|
||||||
else { //not relevant?
|
|
||||||
speedNow = speedTarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------
|
|
||||||
//--- update timer, increment ---
|
|
||||||
//-------------------------------
|
|
||||||
//AT TARGET -> STOP
|
|
||||||
if (stepsToGo == 0) {
|
|
||||||
timer_pause(timerGroup, timerIdx);
|
|
||||||
timerIsRunning = false;
|
|
||||||
speedNow = speedMin;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//STEPS REMAINING -> NEXT STEP
|
|
||||||
//update timer with new speed
|
|
||||||
ESP_ERROR_CHECK(timer_set_alarm_value(timerGroup, timerIdx, TIMER_F / speedNow));
|
|
||||||
|
|
||||||
//generate pulse
|
|
||||||
GPIO.out_w1ts = (1ULL << STEPPER_STEP_PIN); //turn on (fast)
|
|
||||||
ets_delay_us(10);
|
|
||||||
GPIO.out_w1tc = (1ULL << STEPPER_STEP_PIN); //turn off (fast)
|
|
||||||
|
|
||||||
//increment pos
|
|
||||||
stepsToGo --;
|
|
||||||
if (direction == 1){
|
|
||||||
posNow ++;
|
|
||||||
} else {
|
|
||||||
//prevent underflow FIXME this case should not happen in the first place?
|
|
||||||
if (posNow != 0){
|
|
||||||
posNow --;
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG,"isr: posNow would be negative - ignoring decrement");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
//init stepper pins and timer
|
|
||||||
void stepper_init();
|
|
||||||
|
|
||||||
//delay until stepper is stopped, optional timeout in ms, 0 = no limit
|
|
||||||
void stepper_waitForStop(uint32_t timeoutMs = 0);
|
|
||||||
|
|
||||||
//run to limit and define zero/start position. (busy until finished)
|
|
||||||
//Currently simply runs stepper for travelMm and bumps into hardware limit
|
|
||||||
void stepper_home(uint32_t travelMm = 60);
|
|
||||||
|
|
||||||
//set absolute target position in steps
|
|
||||||
void stepper_setTargetPosSteps(uint64_t steps);
|
|
||||||
|
|
||||||
//set absolute target position in millimeters
|
|
||||||
void stepper_setTargetPosMm(uint32_t posMm);
|
|
||||||
|
|
||||||
//set target speed in millimeters per second
|
|
||||||
void stepper_setSpeed(uint32_t speedMmPerS);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//task that periodically logs variables for debugging stepper driver
|
|
||||||
void task_stepper_debug(void *pvParameter);
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
#include "switchesAnalog.hpp"
|
#include "switchesAnalog.hpp"
|
||||||
#include "config.h"
|
|
||||||
#include "global.hpp"
|
|
||||||
|
|
||||||
#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1) //TODO duplicate code: same macro already used in vfd.cpp
|
#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1) //TODO duplicate code: same macro already used in vfd.cpp
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ extern "C"
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
#include "gpio_adc.hpp"
|
#include "gpio_adc.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#include "vfd.hpp"
|
#include "vfd.hpp"
|
||||||
#include "config.h"
|
|
||||||
#include "global.hpp"
|
|
||||||
|
|
||||||
#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)
|
#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ extern "C"
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
|
||||||
//enum defining motor direction
|
//enum defining motor direction
|
||||||
typedef enum vfd_direction_t {FWD, REV} vfd_direction_t;
|
typedef enum vfd_direction_t {FWD, REV} vfd_direction_t;
|
||||||
|
|||||||
@@ -415,6 +415,7 @@ 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
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
Reference in New Issue
Block a user