You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
351 lines
7.1 KiB
351 lines
7.1 KiB
7 years ago
|
// AccelStepper.cpp
|
||
|
//
|
||
|
// Copyright (C) 2009 Mike McCauley
|
||
|
// $Id: AccelStepper.cpp,v 1.2 2010/10/24 07:46:18 mikem Exp mikem $
|
||
|
|
||
|
#include "AccelStepper.h"
|
||
|
|
||
|
void AccelStepper::moveTo(long absolute)
|
||
|
{
|
||
|
_targetPos = absolute;
|
||
|
computeNewSpeed();
|
||
|
}
|
||
|
|
||
|
void AccelStepper::move(long relative)
|
||
|
{
|
||
|
moveTo(_currentPos + relative);
|
||
|
}
|
||
|
|
||
|
// Implements steps according to the current speed
|
||
|
// You must call this at least once per step
|
||
|
// returns true if a step occurred
|
||
|
boolean AccelStepper::runSpeed()
|
||
|
{
|
||
|
unsigned long time = millis();
|
||
|
|
||
|
if (time > _lastStepTime + _stepInterval)
|
||
|
{
|
||
|
if (_speed > 0)
|
||
|
{
|
||
|
// Clockwise
|
||
|
_currentPos += 1;
|
||
|
}
|
||
|
else if (_speed < 0)
|
||
|
{
|
||
|
// Anticlockwise
|
||
|
_currentPos -= 1;
|
||
|
}
|
||
|
step(_currentPos & 0x3); // Bottom 2 bits (same as mod 4, but works with + and - numbers)
|
||
|
|
||
|
_lastStepTime = time;
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
long AccelStepper::distanceToGo()
|
||
|
{
|
||
|
return _targetPos - _currentPos;
|
||
|
}
|
||
|
|
||
|
long AccelStepper::targetPosition()
|
||
|
{
|
||
|
return _targetPos;
|
||
|
}
|
||
|
|
||
|
long AccelStepper::currentPosition()
|
||
|
{
|
||
|
return _currentPos;
|
||
|
}
|
||
|
|
||
|
// Useful during initialisations or after initial positioning
|
||
|
void AccelStepper::setCurrentPosition(long position)
|
||
|
{
|
||
|
_currentPos = position;
|
||
|
}
|
||
|
|
||
|
void AccelStepper::computeNewSpeed()
|
||
|
{
|
||
|
setSpeed(desiredSpeed());
|
||
|
}
|
||
|
|
||
|
// Work out and return a new speed.
|
||
|
// Subclasses can override if they want
|
||
|
// Implement acceleration, deceleration and max speed
|
||
|
// Negative speed is anticlockwise
|
||
|
// This is called:
|
||
|
// after each step
|
||
|
// after user changes:
|
||
|
// maxSpeed
|
||
|
// acceleration
|
||
|
// target position (relative or absolute)
|
||
|
float AccelStepper::desiredSpeed()
|
||
|
{
|
||
|
long distanceTo = distanceToGo();
|
||
|
|
||
|
// Max possible speed that can still decelerate in the available distance
|
||
|
float requiredSpeed;
|
||
|
if (distanceTo == 0)
|
||
|
return 0.0; // Were there
|
||
|
else if (distanceTo > 0) // Clockwise
|
||
|
requiredSpeed = sqrt(2.0 * distanceTo * _acceleration);
|
||
|
else // Anticlockwise
|
||
|
requiredSpeed = -sqrt(2.0 * -distanceTo * _acceleration);
|
||
|
|
||
|
if (requiredSpeed > _speed)
|
||
|
{
|
||
|
// Need to accelerate in clockwise direction
|
||
|
if (_speed == 0)
|
||
|
requiredSpeed = sqrt(2.0 * _acceleration);
|
||
|
else
|
||
|
requiredSpeed = _speed + abs(_acceleration / _speed);
|
||
|
if (requiredSpeed > _maxSpeed)
|
||
|
requiredSpeed = _maxSpeed;
|
||
|
}
|
||
|
else if (requiredSpeed < _speed)
|
||
|
{
|
||
|
// Need to accelerate in anticlockwise direction
|
||
|
if (_speed == 0)
|
||
|
requiredSpeed = -sqrt(2.0 * _acceleration);
|
||
|
else
|
||
|
requiredSpeed = _speed - abs(_acceleration / _speed);
|
||
|
if (requiredSpeed < -_maxSpeed)
|
||
|
requiredSpeed = -_maxSpeed;
|
||
|
}
|
||
|
// Serial.println(requiredSpeed);
|
||
|
return requiredSpeed;
|
||
|
}
|
||
|
|
||
|
// Run the motor to implement speed and acceleration in order to proceed to the target position
|
||
|
// You must call this at least once per step, preferably in your main loop
|
||
|
// If the motor is in the desired position, the cost is very small
|
||
|
// returns true if we are still running to position
|
||
|
boolean AccelStepper::run()
|
||
|
{
|
||
|
if (_targetPos == _currentPos)
|
||
|
return false;
|
||
|
|
||
|
if (runSpeed())
|
||
|
computeNewSpeed();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
AccelStepper::AccelStepper(uint8_t pins, uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4)
|
||
|
{
|
||
|
_pins = pins;
|
||
|
_currentPos = 0;
|
||
|
_targetPos = 0;
|
||
|
_speed = 0.0;
|
||
|
_maxSpeed = 1.0;
|
||
|
_acceleration = 1.0;
|
||
|
_stepInterval = 0;
|
||
|
_lastStepTime = 0;
|
||
|
_pin1 = pin1;
|
||
|
_pin2 = pin2;
|
||
|
_pin3 = pin3;
|
||
|
_pin4 = pin4;
|
||
|
enableOutputs();
|
||
|
}
|
||
|
|
||
|
AccelStepper::AccelStepper(void (*forward)(), void (*backward)())
|
||
|
{
|
||
|
_pins = 0;
|
||
|
_currentPos = 0;
|
||
|
_targetPos = 0;
|
||
|
_speed = 0.0;
|
||
|
_maxSpeed = 1.0;
|
||
|
_acceleration = 1.0;
|
||
|
_stepInterval = 0;
|
||
|
_lastStepTime = 0;
|
||
|
_pin1 = 0;
|
||
|
_pin2 = 0;
|
||
|
_pin3 = 0;
|
||
|
_pin4 = 0;
|
||
|
_forward = forward;
|
||
|
_backward = backward;
|
||
|
}
|
||
|
|
||
|
void AccelStepper::setMaxSpeed(float speed)
|
||
|
{
|
||
|
_maxSpeed = speed;
|
||
|
computeNewSpeed();
|
||
|
}
|
||
|
|
||
|
void AccelStepper::setAcceleration(float acceleration)
|
||
|
{
|
||
|
_acceleration = acceleration;
|
||
|
computeNewSpeed();
|
||
|
}
|
||
|
|
||
|
void AccelStepper::setSpeed(float speed)
|
||
|
{
|
||
|
_speed = speed;
|
||
|
_stepInterval = abs(1000.0 / _speed);
|
||
|
}
|
||
|
|
||
|
float AccelStepper::speed()
|
||
|
{
|
||
|
return _speed;
|
||
|
}
|
||
|
|
||
|
// Subclasses can override
|
||
|
void AccelStepper::step(uint8_t step)
|
||
|
{
|
||
|
switch (_pins)
|
||
|
{
|
||
|
case 0:
|
||
|
step0();
|
||
|
break;
|
||
|
case 1:
|
||
|
step1(step);
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
step2(step);
|
||
|
break;
|
||
|
|
||
|
case 4:
|
||
|
step4(step);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 0 pin step function (ie for functional usage)
|
||
|
void AccelStepper::step0()
|
||
|
{
|
||
|
if (_speed > 0) {
|
||
|
_forward();
|
||
|
} else {
|
||
|
_backward();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 1 pin step function (ie for stepper drivers)
|
||
|
// This is passed the current step number (0 to 3)
|
||
|
// Subclasses can override
|
||
|
void AccelStepper::step1(uint8_t step)
|
||
|
{
|
||
|
digitalWrite(_pin2, _speed > 0); // Direction
|
||
|
// Caution 200ns setup time
|
||
|
digitalWrite(_pin1, HIGH);
|
||
|
// Caution, min Step pulse width for 3967 is 1microsec
|
||
|
// Delay 1microsec
|
||
|
delayMicroseconds(1);
|
||
|
digitalWrite(_pin1, LOW);
|
||
|
}
|
||
|
|
||
|
// 2 pin step function
|
||
|
// This is passed the current step number (0 to 3)
|
||
|
// Subclasses can override
|
||
|
void AccelStepper::step2(uint8_t step)
|
||
|
{
|
||
|
switch (step)
|
||
|
{
|
||
|
case 0: /* 01 */
|
||
|
digitalWrite(_pin1, LOW);
|
||
|
digitalWrite(_pin2, HIGH);
|
||
|
break;
|
||
|
|
||
|
case 1: /* 11 */
|
||
|
digitalWrite(_pin1, HIGH);
|
||
|
digitalWrite(_pin2, HIGH);
|
||
|
break;
|
||
|
|
||
|
case 2: /* 10 */
|
||
|
digitalWrite(_pin1, HIGH);
|
||
|
digitalWrite(_pin2, LOW);
|
||
|
break;
|
||
|
|
||
|
case 3: /* 00 */
|
||
|
digitalWrite(_pin1, LOW);
|
||
|
digitalWrite(_pin2, LOW);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 4 pin step function
|
||
|
// This is passed the current step number (0 to 3)
|
||
|
// Subclasses can override
|
||
|
void AccelStepper::step4(uint8_t step)
|
||
|
{
|
||
|
switch (step)
|
||
|
{
|
||
|
case 0: // 1010
|
||
|
digitalWrite(_pin1, HIGH);
|
||
|
digitalWrite(_pin2, LOW);
|
||
|
digitalWrite(_pin3, HIGH);
|
||
|
digitalWrite(_pin4, LOW);
|
||
|
break;
|
||
|
|
||
|
case 1: // 0110
|
||
|
digitalWrite(_pin1, LOW);
|
||
|
digitalWrite(_pin2, HIGH);
|
||
|
digitalWrite(_pin3, HIGH);
|
||
|
digitalWrite(_pin4, LOW);
|
||
|
break;
|
||
|
|
||
|
case 2: //0101
|
||
|
digitalWrite(_pin1, LOW);
|
||
|
digitalWrite(_pin2, HIGH);
|
||
|
digitalWrite(_pin3, LOW);
|
||
|
digitalWrite(_pin4, HIGH);
|
||
|
break;
|
||
|
|
||
|
case 3: //1001
|
||
|
digitalWrite(_pin1, HIGH);
|
||
|
digitalWrite(_pin2, LOW);
|
||
|
digitalWrite(_pin3, LOW);
|
||
|
digitalWrite(_pin4, HIGH);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Prevents power consumption on the outputs
|
||
|
void AccelStepper::disableOutputs()
|
||
|
{
|
||
|
if (! _pins) return;
|
||
|
|
||
|
digitalWrite(_pin1, LOW);
|
||
|
digitalWrite(_pin2, LOW);
|
||
|
if (_pins == 4)
|
||
|
{
|
||
|
digitalWrite(_pin3, LOW);
|
||
|
digitalWrite(_pin4, LOW);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void AccelStepper::enableOutputs()
|
||
|
{
|
||
|
if (! _pins) return;
|
||
|
|
||
|
pinMode(_pin1, OUTPUT);
|
||
|
pinMode(_pin2, OUTPUT);
|
||
|
if (_pins == 4)
|
||
|
{
|
||
|
pinMode(_pin3, OUTPUT);
|
||
|
pinMode(_pin4, OUTPUT);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Blocks until the target position is reached
|
||
|
void AccelStepper::runToPosition()
|
||
|
{
|
||
|
while (run())
|
||
|
;
|
||
|
}
|
||
|
|
||
|
boolean AccelStepper::runSpeedToPosition()
|
||
|
{
|
||
|
return _targetPos!=_currentPos ? AccelStepper::runSpeed() : false;
|
||
|
}
|
||
|
|
||
|
// Blocks until the new target position is reached
|
||
|
void AccelStepper::runToNewPosition(long position)
|
||
|
{
|
||
|
moveTo(position);
|
||
|
runToPosition();
|
||
|
}
|
||
|
|