File StepperMotor.h
File List > Drivers > StepperMotor > StepperMotor.h
Go to the documentation of this file
#pragma once
#ifdef ARDUINO_ARCH_STM32
#include <PanelGroup.h> // PinRef
#include <Drivers/MotorDriver/MotorDriver.h> // MotorDriver base
namespace OpenSkyhawk {
enum class HomeMode : uint8_t {
STALL,
SENSOR
// ABSOLUTE — future: read an absolute encoder (AS5600); reports position, no seek.
};
enum class StepPattern : uint8_t {
SWITEC_6STATE,
FULL_4STATE
};
struct AccelPoint {
uint16_t stepThreshold;
uint16_t delayUs;
};
struct HomeSensor {
bool activeLow;
uint8_t debounceMs;
uint16_t maxSeekSteps;
};
struct StepperConfig {
uint16_t stepsPerRev;
StepPattern pattern;
const AccelPoint* accel;
uint8_t accelN;
HomeMode home;
bool homeSeekClockwise;
HomeSensor sensor;
int16_t homePosition;
int16_t parkPosition;
int16_t minPos;
int16_t maxPos;
bool wrap;
uint8_t deadband;
bool autoRecal;
uint32_t recalDebounceMs;
// Appended for back-compat: existing positional initialisers omit these → value-initialised to
// 0 → legacy behaviour (STALL home drives stepsPerRev at the library default rate).
uint16_t rangeSteps;
uint16_t homeStepUs;
};
extern const AccelPoint kSwitecDefaultAccel[5];
constexpr uint8_t kSwitecDefaultAccelN = 5;
StepperConfig makeX27Config(int16_t homePosition, int16_t parkPosition,
int16_t minPos, int16_t maxPos,
HomeMode home = HomeMode::STALL,
bool homeSeekClockwise = false,
HomeSensor sensor = { true, 5, 2000 },
bool wrap = false, uint8_t deadband = 1,
bool autoRecal = false, uint32_t recalDebounceMs = 0,
uint16_t stepsPerRev = 1080, uint16_t rangeSteps = 945,
uint16_t homeStepUs = 0);
class StepperMotor : public MotorDriver {
public:
StepperMotor(PinRef c1, PinRef c2, PinRef c3, PinRef c4, const StepperConfig& cfg,
PinRef homeSense = PinRef(), PinRef sleepEn = PinRef());
void configure() override;
void home() override;
void moveTo(int32_t pos) override;
void update() override;
int32_t position() const override;
bool homed() const { return _homed; }
#ifdef STEPPERMOTOR_TEST
void debugAdvance() { advance(); }
int32_t debugCurrentStep() const { return _currentStep; }
int32_t debugTargetStep() const { return _targetStep; }
uint16_t debugVel() const { return _vel; }
uint16_t debugMicroDelay() const { return _microDelay; }
bool debugStopped() const { return _stopped; }
bool debugSensorAsserted() const { return sensorAsserted(false); }
void debugSetSensorOverride(int8_t level) { _sensorOverride = level; }
#endif
private:
// collaborators / config (plain // — EXTRACT_PRIVATE NO, not in API docs)
PinRef _coil[4]; // coil pins
PinRef _homeSense; // home sensor (NC if unused)
PinRef _sleepEn; // driver enable / ~SLEEP (NC if unused)
StepperConfig _cfg; // copied config (accel table referenced, not owned)
uint16_t _maxVel; // last accel threshold = top speed gate
// motion state (SwitecX25 model)
int32_t _currentStep; // absolute step position
int32_t _targetStep; // commanded target
uint16_t _vel; // accel-steps proxy for velocity
int8_t _dir; // +1 / -1 / 0
bool _stopped; // true when settled at target
uint8_t _state; // coil-state index (0..stateCount-1)
uint16_t _microDelay; // delay until next step, µs
uint32_t _time0; // micros() at last step
bool _homed; // homing succeeded
// auto-recal
uint32_t _lastRecalMs; // millis() of last recal
int8_t _sensorOverride; // -1 = read pin; 0/1 = forced (test seam)
// helpers
void writeIO(); // energise coils for _state
void stepOnce(bool up); // one detent in a direction
void advance(); // SwitecX25 accel/step kernel
bool sensorAsserted(bool live) const; // single read through activeLow; live=true → bypass cache
bool sensorConfirmed() const; // sensorAsserted stable for debounceMs
bool seekHomeBlocking(); // step toward sensor until confirmed or maxSeekSteps
void runToStopBlocking(); // advance() + delay until stopped (homing/park moves)
};
} // namespace OpenSkyhawk
#endif // ARDUINO_ARCH_STM32