stepper

nkrkv/stepdir/stepper

Drives a stepper motor connected through a driver with step/direction interface. Uses hardware timer to generate a pulse train of the required frequency. Depending on the board model several motors can be in conflict.
stepper
@/stepper
Drives a stepper motor connected through a driver with step/direction interface. Uses hardware timer to generate a pulse train of the required frequency. Depending on the board model several motors can be in conflict.
STEPport
A board port to which the step port of the driver is connected.
DIRport
A board port to which the direction port of the driver is connected.
PPSnumber
Pulses per second. Defines the rotation speed: number of steps a motor is expected to perform in one second. Should not be zero. The upper limit is defined by characteristics of the connected motor.
Nnumber
Number of steps to make. Many motors have 200 or 400 steps per revolution. Pass a negative value to rotate in the backward direction. Set to `+Inf` or `-Inf` to run an infinite rotation.
GOpulse
Starts a new rotation which will make `N` steps at `PPS` rate.
RSTpulse
Reset. Cancels the current rotation. Neither `DONE` nor `ERR` will fire after a pulse on `RST`.
stepper
STEP
DIR
PPS
N
GO
RST
DONE
ERR
ERRpulse
Fires when the rotation is impossible. For example, if the value of `PPS` is wrong.
DONEpulse
Fires when `N` steps complete successfully.
To use the node in your project you should have the nkrkv/stepdir library installed. Use the “File → Add Library” menu item in XOD IDE if you don’t have it yet. See Using libraries for more info.

C++ implementation

struct State {
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
    auto stepPort = getValue<input_STEP>(ctx);
    auto dirPort = getValue<input_DIR>(ctx);
    auto nSteps = getValue<input_N>(ctx);
    auto pps = getValue<input_PPS>(ctx);

    if (isInputDirty<input_RST>(ctx)) {
        noTone(stepPort);
        clearTimeout(ctx);
        return;
    }

    if (isTimedOut(ctx)) {
        emitValue<output_DONE>(ctx, 1);
    }

    if (!isInputDirty<input_GO>(ctx)) {
        return;
    }

    if (pps == 0) {
        emitValue<output_ERR>(ctx, 1);
        return;
    }

    if (pps < 0) {
        // swap direction if PPS is negative
        pps = -pps;
        nSteps = -nSteps;
    }

    // In case the in-progress rotation is finite and the upcoming
    // one will be infinite
    clearTimeout(ctx);

    pinMode(stepPort, OUTPUT);
    pinMode(dirPort, OUTPUT);
    digitalWrite(dirPort, nSteps < 0);

    if (isfinite(nSteps)) {
        unsigned long durationMs = abs(nSteps) / pps * 1000;
        tone(stepPort, pps, durationMs);
        setTimeout(ctx, durationMs);
    } else {
        tone(stepPort, pps);
    }
}