0

So I tried to implement an S-Curve for the movement of my stepper motor; however, I feel like this is way too complicated for the simple thing I want the stepper motor to do: Smooth movement. It doesn't have to go from a to b within the blink of an eye, just smoothly. Also, the function overshoots by a gigantic amount of steps (pos_err is almost 40% of steps, always).

void stepper_t::step(int32_t steps, direction dir)
{

    float32_t pulse_delay;      /* Stepper pulse delay [microsec] */

    int8_t count = 0;           /* Count the number of pulses */
    int32_t pos_err = 0;        /* Error in position */

    int16_t speed = 3200;       /* Steady state velocity [pulse/s] */

    int8_t var = 0;

    int32_t move_time = (steps / (speed / 1000000));                    /* Total time moving */
    int32_t accel_time = move_time < 30000 ? (move_time / 2) : 30000;   /* Acceleration time [microsec] */
    int32_t decel_time = move_time < 30000 ? (move_time / 2) : 30000;   /* Deceleration time [microsec] */
    int32_t constant_speed = move_time - (accel_time + decel_time);     /* Time during constant velocity [microsec] */

    int32_t curr_time = decel_time / 30; /* Current time     [microsec] 
                                            You need to seed the initial time 
                                            with something > 0 so you don't 
                                            calculate too long of a delay */

    this->set_direction(dir);

    while (var < 1) {         
        if (curr_time < accel_time) {  
            /* Acceleration */                                     
            pulse_delay = ((float32_t) accel_time / (2.f * ((float32_t) speed / 1000000.f) * (float32_t) curr_time));
        } else if ((curr_time >= accel_time) && (curr_time < (accel_time + constant_speed))) {      
            /* Constant velocity */
            pulse_delay = (1.f / (2.f * ((float32_t) speed / 1000000.f)));
        } else if ((curr_time >= (accel_time + constant_speed)) && (curr_time < (accel_time + constant_speed + decel_time))) {    
            /* Deceleration */
            pulse_delay = (1.f / (2.f * (((float32_t) speed / 1000000.f) - ((float32_t) speed / (1000000.f * (float32_t) decel_time)) * ((float32_t) curr_time - (float32_t) accel_time - (float32_t) constant_speed))));
        }

        /* Time is incremented by pulse delay twice due to the pin going
        high, then low, delaying twice */
        curr_time = curr_time + (int32_t) (float32_t) (2.f * pulse_delay);

        /* Send pulse with calculated delay */
        Chip_GPIO_SetPinState(LPC_GPIO_PORT, this->GPIO_step_port, this->GPIO_step_pin, true);
        OS_Delayus((OS_U16) pulse_delay);
        Chip_GPIO_SetPinState(LPC_GPIO_PORT, this->GPIO_step_port, this->GPIO_step_pin, false);
        OS_Delayus((OS_U16) pulse_delay);

        count++;

        /* Correct for any position error due to rounding */
        if (curr_time > (accel_time + constant_speed + decel_time)) {
            pos_err = steps - count;

            if (pos_err < 0) {
                pos_err = -1 * pos_err;

                if (dir == OUTWARD) {
                    this->set_direction(INWARD);
                } else {
                    this->set_direction(OUTWARD);
                }
            }

            for (; pos_err > 0; pos_err--) {
                Chip_GPIO_SetPinState(LPC_GPIO_PORT, this->GPIO_step_port, this->GPIO_step_pin, true);
                OS_Delayus((OS_U16) pulse_delay);
                Chip_GPIO_SetPinState(LPC_GPIO_PORT, this->GPIO_step_port, this->GPIO_step_pin, false);
                OS_Delayus((OS_U16) pulse_delay);
            }

            count = 0;
            curr_time = decel_time / 9;
            var++;
        }
    }
}

Why wouldn't I just use a cosine to calculate the delays in between like this?

void step2(int32_t steps) {

    int8_t count = 0;
    float32_t delay;

    while (count < steps) {
        delay = (cos ( (PI * 2 * count)/steps ) + 1) * 5000 + 10000;
        Chip_GPIO_SetPinState(LPC_GPIO_PORT, this->GPIO_step_port, this->GPIO_step_pin, true);
        OS_Delayus((OS_U16) delay);
        Chip_GPIO_SetPinState(LPC_GPIO_PORT, this->GPIO_step_port, this->GPIO_step_pin, false);
        OS_Delayus((OS_U16) delay);
        count++;
    }
}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
GSerum_
  • 57
  • 8
  • 1
    Unfortunately your question doesn't have clearly defined problem that could be answered in a few paragraphs. Question in it's current state will most likely require lenghty tutorial to be any useful, and such things are off topic here. Please narrow your question somekind of concrete problem that can be answered. – user694733 Dec 11 '19 at 13:14
  • 1
    tooooooooo broad. Start studing something about microstepping and PIDs andtrajectory generation. Google it. – LPs Dec 11 '19 at 13:17
  • If you edit this post to [include the code](https://stackoverflow.com/help/minimal-reproducible-example) you have used in an attempt to do what you have described, and in the post also pointed out specifically where it is deficient, (buggy, bad performance, etc., which you have kind of done ) this question would get a much more usable response. – ryyker Dec 11 '19 at 13:30
  • Thanks for the reply, I've attached the code and hopefully narrowed down my question. – GSerum_ Dec 11 '19 at 13:38
  • Some 20 years ago I worked on such a stepper software for a 3D machine. We didn't use trigonomy functions, but simple linear acceleration and deceleration. So it was easy to calculate the frequency and its changes for each axis. Note, that especially for the final ramp you need to do some calculation *before* you start your vector. – the busybee Dec 12 '19 at 07:22

0 Answers0