9 Commits

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

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

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

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

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

Test: broken - slow moves mork but when "extending" movement it just
vibrates
2023-03-13 18:26:50 +01:00
jonny_ji7
45409676a0 Stepper: add mutex, logging, delay, less steps
When testing last commit the stepper task crashed almost instantly and
moved randomly. Trying to fix/debug that with those changes
2023-03-13 11:12:42 +01:00
jonny_ji7
de42b6252e Stepper: Add resume/update functionality (WIP)
add way to extend current move operation without having to wait for IDLE
state (full decel time)
2023-03-12 13:06:30 +01:00
9 changed files with 346 additions and 1541 deletions

View File

@@ -55,6 +55,9 @@ void DendoStepper::init(uint8_t stepP, uint8_t dirP, uint8_t enP, timer_group_t
void DendoStepper::init()
{
ESP_LOGW("DendoStepper", "semaphore init");
semaphore_isrVariables = xSemaphoreCreateBinary();
xSemaphoreGive(semaphore_isrVariables);
uint64_t mask = (1ULL << conf.stepPin) | (1ULL << conf.dirPin) | (1ULL << conf.enPin); // put output gpio pins in bitmask
gpio_config_t gpio_conf = {
// config gpios
@@ -114,25 +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_err_t DendoStepper::runPos(int32_t relative)
{
if (!relative) // why would u call it with 0 wtf
return ESP_ERR_NOT_SUPPORTED;
if (ctrl.status > IDLE)
{ // we are running, we need to adjust steps accordingly, for now just stop the movement
STEP_LOGW("DendoStepper", "Finising previous move, this command will be ignored");
return ESP_ERR_NOT_SUPPORTED;
}
//TODO only enable when actually moving
if (ctrl.status == DISABLED) // if motor is disabled, enable it
enableMotor();
ctrl.status = ACC;
setDir(relative < 0); // set CCW if <0, else set CW
currentPos += relative;
if (!relative) // why would u call it with 0 wtf
return ESP_ERR_NOT_SUPPORTED;
if (ctrl.status > IDLE) { //currently moving
//ctrl.status = ctrl.status==COAST ? COAST : ACC; //stay at coast otherwise switch to ACC
ctrl.stepsRemaining = ctrl.stepsToGo - ctrl.stepCnt;
calc(abs(relative) + ctrl.stepsRemaining); //calculate new velolcity profile for new+remaining steps
ESP_LOGW("DendoStepper", "EXTEND running movement (stepsRemaining: %d + stepsNew: %d - current state: %d)", ctrl.stepsRemaining, abs(relative), (int)ctrl.status);
ESP_ERROR_CHECK(timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval)); // set HW timer alarm to stepinterval
}
else { //current state is IDLE
//ctrl.statusPrev = ctrl.status; //update previous status
calc(abs(relative)); // calculate velocity profile
ctrl.status = ACC;
ESP_ERROR_CHECK(timer_set_alarm_value(conf.timer_group, conf.timer_idx, ctrl.stepInterval)); // set HW timer alarm to stepinterval
ESP_ERROR_CHECK(timer_start(conf.timer_group, conf.timer_idx)); // start the timer
}
//printf("runpos end -- steps: %d, status: %d, olddir: %d, newdir: %d\n", relative, ctrl.status, ctrl.dir, newDir);
currentPos += relative; //(target position / not actual)
return ESP_OK;
}
@@ -145,26 +159,31 @@ esp_err_t DendoStepper::runPosMm(int32_t relative)
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)
{
if (getState() > IDLE) // we are already moving, so stop it
stop();
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;
//exit if nothing to do
if (position == currentPos) return 0; //already at position
//calculate steps necessary
int32_t relativeSteps = 0;
relativeSteps = (int32_t)position - currentPos;
//wait if direction needs to change
if (getState() > IDLE){//already moving
bool newDir = (relativeSteps < 0); // CCW if <0, else set CW
if (ctrl.dir != newDir){ //direction differs
STEP_LOGE("DendoStepper", "DIRECTION HOT-CHANGE NOT SUPPORTED - Waiting for move to finish...");
while (getState() > IDLE) vTaskDelay(5); //wait for move to finish
}
}
//call runPos with new target position
ESP_LOGI("DendoStepper", "Cur: %llu move %d", currentPos, relativeSteps);
return runPos(relativeSteps); // run to new position
}
esp_err_t DendoStepper::runAbsMm(uint32_t position)
{
if (ctrl.stepsPerMm == 0)
@@ -195,6 +214,37 @@ void DendoStepper::setSpeedMm(uint32_t speed, uint16_t accT, uint16_t decT)
STEP_LOGI("DendoStepper", "Speed set: v=%d mm/s t+=%d s t-=%d s", speed, accT, decT);
}
//CUSTOM - change speed while running
//FIXME: this approach does not work, since calc function would have to be run after change, this will mess up target steps...
//void DendoStepper::changeSpeed(uint32_t speed)
//{
// //TODO reduce duplicate code (e.g. call setSpeed function)
// //change speed
// ctrl.speed = speed;
// //change status to ACC/DEC
// STEP_LOGI("DendoStepper", "Speed changed: from v=%.2f rad/s to v=%.2f rad/s", ctrl.speed, speed);
// if (speed > ctrl.speed) ctrl.status = ACC;
// if (speed < ctrl.speed) ctrl.status = DEC;
//}
//
//void DendoStepper::changeSpeedMm(uint32_t speed)
//{
// //TODO reduce duplicate code (e.g. call setSpeedMm function)
// if (ctrl.stepsPerMm == 0)
// {
// STEP_LOGE("DendoStepper", "Steps per millimeter not set, cannot set the speed!");
// }
// //calc new speed
// float speedNew = speed * ctrl.stepsPerMm;
// //change status to ACC/DEC
// if (speedNew > ctl.speed) ctrl.status = ACC;
// if (speedNew < ctl.speed) ctrl.status = DEC;
// //update speed, log output
// ctrl.speed = speedNew;
// STEP_LOGI("DendoStepper", "Speed changed: from v=%.2f rad/s to v=%.2f rad/s", ctrl.speed, speedNew);
//}
void DendoStepper::setStepsPerMm(uint16_t steps)
{
ctrl.stepsPerMm = steps;
@@ -261,6 +311,7 @@ void DendoStepper::stop()
}
ctrl.runInfinite = false;
timer_pause(conf.timer_group, conf.timer_idx); // stop the timer
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = IDLE;
ctrl.stepCnt = 0;
gpio_set_level((gpio_num_t)conf.stepPin, 0);
@@ -287,10 +338,23 @@ bool DendoStepper::xISR()
ctrl.stepCnt++;
////CUSTOM: track actual precice current position
//if (ctrl.dir) {
// ctrl.posActual ++;
//} else {
// ctrl.posActual --;
//}
//CUSTOM: track remaining steps for eventually resuming
//xSemaphoreTake(semaphore_isrVariables, portMAX_DELAY);
//ctrl.stepsRemaining = ctrl.stepCnt - ctrl.stepCnt;
//xSemaphoreGive(semaphore_isrVariables);
// we are done
if (ctrl.stepsToGo == ctrl.stepCnt && !ctrl.runInfinite)
{
timer_pause(conf.timer_group, conf.timer_idx); // stop the timer
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = IDLE;
ctrl.stepCnt = 0;
return 0;
@@ -299,16 +363,19 @@ bool DendoStepper::xISR()
if (ctrl.stepCnt > 0 && ctrl.stepCnt < ctrl.accEnd)
{ // we are accelerating
ctrl.currentSpeed += ctrl.accInc;
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = ACC; // we are accelerating, note that*/
}
else if (ctrl.stepCnt > ctrl.coastEnd && !ctrl.runInfinite)
{ // we must be deccelerating then
ctrl.currentSpeed -= ctrl.decInc;
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = DEC; // we are deccelerating
}
else
{
ctrl.currentSpeed = ctrl.targetSpeed;
//ctrl.statusPrev = ctrl.status; //update previous status
ctrl.status = COAST; // we are coasting
}
@@ -321,17 +388,33 @@ bool DendoStepper::xISR()
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
ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc);
//steps from ctrl.speed -> 0:
ctrl.decSteps = 0.5 * ctrl.dec * (ctrl.speed / ctrl.dec) * (ctrl.speed / ctrl.dec);
ESP_LOGD("DendoStepper", "decSteps: %d currspeed: %lf, ctrlSpeed: %lf\n", ctrl.decSteps, ctrl.currentSpeed, ctrl.speed);
//steps from 0 -> ctrl.speed:
//ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc);
//steps from ctrl.currentSpeed -> ctrl.speed:
ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc) * (ctrl.speed - ctrl.currentSpeed) / ctrl.speed;
ESP_LOGD("DendoStepper", "accSteps: %d currspeed: %lf, ctrlSpeed: %lf\n", ctrl.accSteps, ctrl.currentSpeed, ctrl.speed);
if (targetSteps < (ctrl.decSteps + ctrl.accSteps))
{
ESP_LOGI("Dendostepper", "Computing new speed");
ctrl.speed = sqrt(2 * targetSteps * ((ctrl.dec * ctrl.acc) / (ctrl.dec + ctrl.acc)));
ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc);
//ctrl.accSteps = 0.5 * ctrl.acc * (ctrl.speed / ctrl.acc) * (ctrl.speed / ctrl.acc);
ctrl.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);
}
@@ -339,13 +422,27 @@ void DendoStepper::calc(uint32_t targetSteps)
ctrl.coastEnd = targetSteps - ctrl.decSteps;
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;
//only set initial speed if IDLE
if(ctrl.status == 1){
ctrl.currentSpeed = ctrl.accInc;
ESP_LOGD("DendoStepper", "`reset curr speeed to accinc: %lf\n", ctrl.currentSpeed);
ESP_LOGD("DendoStepper", "status=%d setting speed to initial value: %lf\n",ctrl.status, ctrl.currentSpeed);
}
else{
ESP_LOGD("DendoStepper", "status=%d NOT resetting speed to initial value %lf\n",ctrl.status, ctrl.currentSpeed);
}
ctrl.stepInterval = TIMER_F / ctrl.currentSpeed;
ctrl.stepsToGo = targetSteps;
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);
}

View File

@@ -29,6 +29,7 @@
#include "freertos/task.h"
#include "esp_timer.h"
#include "math.h"
#include "freertos/semphr.h"
//#define STEP_DEBUG
@@ -94,6 +95,9 @@ typedef struct
float dec = 100; // decceleration in rad*second^-2
uint32_t accSteps = 0;
uint32_t decSteps = 0;
int32_t stepsRemaining = 0;
//uint64_t posActual = 0; //actual current pos incremented at every step
uint8_t statusPrev = DISABLED; //FIXME currently unused
uint8_t status = DISABLED;
bool dir = CW;
bool runInfinite = false;
@@ -108,6 +112,7 @@ private:
ctrl_var_t ctrl;
esp_timer_handle_t dyingTimer;
TaskHandle_t enTask;
SemaphoreHandle_t semaphore_isrVariables = NULL;
uint64_t currentPos = 0; // absolute position
bool timerStarted = 0;
@@ -208,6 +213,9 @@ public:
*/
void setSpeedMm(uint32_t speed, uint16_t accT, uint16_t decT);
//CUSTOM: change speed while running
void changeSpeedMm(uint32_t speed);
/**
* @brief Set steps per 1 mm of linear movement
*

File diff suppressed because one or more lines are too long

View File

@@ -8,7 +8,6 @@ idf_component_register(
"display.cpp"
"cutter.cpp"
"switchesAnalog.cpp"
"stepper.cpp"
"guide-stepper.cpp"
"encoder.cpp"
INCLUDE_DIRS

View File

@@ -85,7 +85,7 @@ extern "C" {
//----- stepper config -----
//--------------------------
//enable stepper test mode (dont start control and encoder task)
#define STEPPER_TEST
//#define STEPPER_TEST
#define STEPPER_STEP_PIN GPIO_NUM_18 //mos1
#define STEPPER_DIR_PIN GPIO_NUM_16 //ST3
#define STEPPER_EN_PIN GPIO_NUM_0 //not connected (-> stepper always on)

View File

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

View File

@@ -17,8 +17,6 @@ extern "C"
#include "guide-stepper.hpp"
#include "encoder.hpp"
#include "stepper.hpp"
//=================================
//=========== functions ===========
@@ -89,19 +87,18 @@ extern "C" void app_main()
esp_log_level_set("switches-analog", ESP_LOG_WARN);
esp_log_level_set("control", ESP_LOG_INFO);
esp_log_level_set("stepper", ESP_LOG_DEBUG);
esp_log_level_set("Dendostepper", ESP_LOG_WARN); //stepper lib
esp_log_level_set("DendoStepper", ESP_LOG_DEBUG); //stepper lib
esp_log_level_set("calc", ESP_LOG_WARN); //stepper lib
#ifdef STEPPER_TEST
//create task for stepper testing
xTaskCreate(task_stepper_test, "task_stepper_test", configMINIMAL_STACK_SIZE * 3, NULL, 2, NULL);
//xTaskCreate(task_stepper_debug, "task_stepper_test", configMINIMAL_STACK_SIZE * 3, NULL, 2, NULL);
xTaskCreate(task_stepper_test, "task_stepper_test", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
#else
//create task for controlling the machine
xTaskCreate(task_control, "task_control", configMINIMAL_STACK_SIZE * 3, NULL, 4, NULL);
xTaskCreate(task_control, "task_control", configMINIMAL_STACK_SIZE * 3, NULL, 5, NULL);
//create task for controlling the stepper
xTaskCreate(task_stepper_ctl, "task_stepper_ctl", configMINIMAL_STACK_SIZE * 3, NULL, 2, NULL);
//create task for controlling the machine
xTaskCreate(task_stepper_ctl, "task_stepper_ctl", configMINIMAL_STACK_SIZE * 5, NULL, 5, NULL);
#endif
//create task for handling the buzzer

View File

@@ -1,249 +0,0 @@
//custom driver for stepper motor
#include "config.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"
}
//config from config.hpp
//#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
#define STEPPER_SPEED_DEFAULT 20 //mm/s
#define STEPPER_SPEED_MIN 4 //mm/s - speed at which stepper immediately starts/stops
#define STEPPER_ACCEL_INC 3 //steps/s per cycle
#define STEPPER_DECEL_INC 8 //steps/s 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-ctl"; //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_LOGW(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_LOGW(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_LOGW(TAG, "starting timer because did not run before");
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_LOGW(TAG, "set target position to %u mm", posMm);
stepper_setTargetPosSteps(posMm * STEPPER_STEPS_PER_MM);
}
//========================
//===== init stepper =====
//========================
void stepper_init(){
ESP_LOGW(TAG, "init - configure struct...");
// Configure pulse and direction pins as outputs
ESP_LOGW(TAG, "init - configure gpio pins...");
gpio_set_direction(STEPPER_DIR_PIN, GPIO_MODE_OUTPUT);
gpio_set_direction(STEPPER_STEP_PIN, GPIO_MODE_OUTPUT);
ESP_LOGW(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
if (stepsToGo <= stepsDecelRemaining) {
//FIXME if stepsToGo gets updated (lowered) close to target while close to target, the stepper may stop too fast -> implement possibility to 'overshoot and reverse'?
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;
}

View File

@@ -1,13 +0,0 @@
#pragma once
//init stepper pins and timer
void stepper_init();
//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);