具體的講解見:
https://www.youtube.com/watch?v=fHAO7SW-SZI&t=1308s
文中的電機特性文檔見:
鏈接:https://pan.baidu.com/s/1WdZ-yWIUyPWmhbD_X1_6FQ
提取碼:lc99
複製這段內容後打開百度網盤手機App,操作更方便哦
1 簡單控制
#define DIR_PIN 2
#define STEP_PIN 3
#define ENABLE_PIN 4
void setup() {
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
digitalWrite(ENABLE_PIN, LOW);
}
void loop() {
digitalWrite(STEP_PIN, HIGH);
digitalWrite(STEP_PIN, LOW);
delay(1);
}
2 恆速控制
#define DIR_PIN 2
#define STEP_PIN 3
#define ENABLE_PIN 4
void setup() {
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
}
void simpleMove(int steps) {
int interval = 100;
for (int i = 0; i < steps; i++) {
digitalWrite(STEP_PIN, HIGH);
digitalWrite(STEP_PIN, LOW);
delayMicroseconds(interval);
}
}
void loop() {
digitalWrite(DIR_PIN, LOW);
simpleMove(800);
digitalWrite(DIR_PIN, HIGH);
simpleMove(800);
while (true);
}
3 簡單的加速
#define DIR_PIN 2
#define STEP_PIN 3
#define ENABLE_PIN 4
void setup() {
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
}
void simpleAccel(int steps) {
int lowSpeed = 2000;
int highSpeed = 100;
int change = 2;
int rampUpStop = (lowSpeed - highSpeed) / change;
if ( rampUpStop > steps / 2 )
rampUpStop = steps / 2;
int rampDownStart = steps - rampUpStop;
int d = lowSpeed;
for (int i = 0; i < steps; i++) {
digitalWrite(STEP_PIN, HIGH);
digitalWrite(STEP_PIN, LOW);
delayMicroseconds(d);
if ( i < rampUpStop )
d -= change;
else if ( i > rampDownStart )
d += change;
}
}
void loop() {
digitalWrite(DIR_PIN, LOW);
simpleAccel(2400);
digitalWrite(DIR_PIN, HIGH);
simpleAccel(2400);
while (true);
}
4 恆定加速度
#define DIR_PIN 2
#define STEP_PIN 3
#define ENABLE_PIN 4
void setup() {
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
}
#define STEPS 400
void constantAccel() {
int delays[STEPS];
float angle = 1;
float accel = 0.01;
float c0 = 2000 * sqrt( 2 * angle / accel ) * 0.67703;
float lastDelay = 0;
int highSpeed = 100;
for (int i = 0; i < STEPS; i++) {
float d = c0;
if ( i > 0 )
d = lastDelay - (2 * lastDelay) / (4 * i + 1);
if ( d < highSpeed )
d = highSpeed;
delays[i] = d;
lastDelay = d;
}
// use delays from the array, forward
for (int i = 0; i < STEPS; i++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds( delays[i] );
digitalWrite(STEP_PIN, LOW);
}
// use delays from the array, backward
for (int i = 0; i < STEPS; i++) {
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds( delays[STEPS-i-1] );
digitalWrite(STEP_PIN, LOW);
}
}
void loop() {
digitalWrite(DIR_PIN, LOW);
constantAccel();
digitalWrite(DIR_PIN, HIGH);
constantAccel();
while (true);
}
5 恆定加速度帶中斷
#define DIR_PIN 2
#define STEP_PIN 3
#define ENABLE_PIN 4
#define STEP_HIGH PORTD |= 0b00001000;
#define STEP_LOW PORTD &= ~0b00001000;
#define TIMER1_INTERRUPTS_ON TIMSK1 |= (1 << OCIE1A);
#define TIMER1_INTERRUPTS_OFF TIMSK1 &= ~(1 << OCIE1A);
unsigned int c0;
void setup() {
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 1000;
TCCR1B |= (1 << WGM12);
TCCR1B |= ((1 << CS11) | (1 << CS10));
interrupts();
c0 = 1600; // was 2000 * sqrt( 2 * angle / accel )
}
volatile int dir = 0;
volatile unsigned int maxSpeed = 10;
volatile unsigned long n = 0;
volatile float d;
volatile unsigned long stepCount = 0;
volatile unsigned long rampUpStepCount = 0;
volatile unsigned long totalSteps = 0;
volatile int stepPosition = 0;
volatile bool movementDone = false;
ISR(TIMER1_COMPA_vect)
{
if ( stepCount < totalSteps ) {
STEP_HIGH
STEP_LOW
stepCount++;
stepPosition += dir;
}
else {
movementDone = true;
TIMER1_INTERRUPTS_OFF
}
if ( rampUpStepCount == 0 ) { // ramp up phase
n++;
d = d - (2 * d) / (4 * n + 1);
if ( d <= maxSpeed ) { // reached max speed
d = maxSpeed;
rampUpStepCount = stepCount;
}
if ( stepCount >= totalSteps / 2 ) { // reached halfway point
rampUpStepCount = stepCount;
}
}
else if ( stepCount >= totalSteps - rampUpStepCount ) { // ramp down phase
n--;
d = (d * (4 * n + 1)) / (4 * n + 1 - 2);
}
OCR1A = d;
}
void moveNSteps(long steps) {
digitalWrite(DIR_PIN, steps < 0 ? HIGH : LOW);
dir = steps > 0 ? 1 : -1;
totalSteps = abs(steps);
d = c0;
OCR1A = d;
stepCount = 0;
n = 0;
rampUpStepCount = 0;
movementDone = false;
TIMER1_INTERRUPTS_ON
}
void moveToPosition(long p, bool wait = true) {
moveNSteps(p - stepPosition);
while ( wait && ! movementDone );
}
void loop() {
moveToPosition( 1600 );
moveToPosition( -1600 );
moveToPosition( 0 );
moveToPosition( 200 );
moveToPosition( 400 );
moveToPosition( 600 );
moveToPosition( 800 );
moveToPosition( 400 );
moveToPosition( 600 );
moveToPosition( 200 );
moveToPosition( 400 );
moveToPosition( 0 );
maxSpeed = 600;
moveToPosition( 200 );
moveToPosition( 400 );
maxSpeed = 400;
moveToPosition( 600 );
moveToPosition( 800 );
maxSpeed = 200;
moveToPosition( 1000 );
moveToPosition( 1200 );
maxSpeed = 10;
moveToPosition( 0 );
while (true);
}
6
#define DIR_PIN 2
#define STEP_PIN 3
#define ENABLE_PIN 4
#define STEP_HIGH PORTD |= 0b00001000;
#define STEP_LOW PORTD &= ~0b00001000;
#define TIMER1_INTERRUPTS_ON TIMSK1 |= (1 << OCIE1A);
#define TIMER1_INTERRUPTS_OFF TIMSK1 &= ~(1 << OCIE1A);
unsigned int c0;
void setup() {
Serial.begin(9600);
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN, OUTPUT);
pinMode(ENABLE_PIN, OUTPUT);
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 1000;
TCCR1B |= (1 << WGM12);
TCCR1B |= ((1 << CS11) | (1 << CS10));
interrupts();
c0 = 1600; //2000 * sqrt( 1 ) * 0.67703;
}
volatile int dir = 0;
volatile unsigned int maxSpeed = 80;
volatile unsigned long n = 0;
volatile float d;
volatile unsigned long stepCount = 0;
volatile unsigned long rampUpStepCount = 0;
volatile unsigned long totalSteps = 0;
volatile int stepPosition = 0;
volatile bool movementDone = false;
ISR(TIMER1_COMPA_vect)
{
if ( stepCount < totalSteps ) {
STEP_HIGH
STEP_LOW
stepCount++;
stepPosition += dir;
}
else {
movementDone = true;
TIMER1_INTERRUPTS_OFF
}
if ( rampUpStepCount == 0 ) { // ramp up phase
n++;
d = d - (2 * d) / (4 * n + 1);
if ( d <= maxSpeed ) {
d = maxSpeed;
rampUpStepCount = stepCount;
}
if ( stepCount >= totalSteps / 2 ) {
rampUpStepCount = stepCount;
}
}
else if ( stepCount >= totalSteps - rampUpStepCount ) { // ramp down phase
n--;
d = (d * (4 * n + 1)) / (4 * n + 1 - 2);
}
OCR1A = d;
}
void moveNSteps(int steps) {
digitalWrite(DIR_PIN, steps < 0 ? HIGH : LOW);
dir = steps > 0 ? 1 : -1;
totalSteps = abs(steps);
d = c0;
OCR1A = d;
stepCount = 0;
n = 0;
rampUpStepCount = 0;
movementDone = false;
TIMER1_INTERRUPTS_ON
}
void moveToPosition(int p, bool wait = true) {
moveNSteps(p - stepPosition);
while ( wait && ! movementDone );
}
void loop() {
Serial.println("Starting...");
moveToPosition( 8000, false );
int count = 0;
while ( !movementDone ) {
if ( count > 3 ) {
movementDone = true;
TIMER1_INTERRUPTS_OFF
}
else {
Serial.print(count++);
Serial.print(" ");
Serial.println( stepPosition );
delay(500);
}
}
Serial.println("Finished.");
Serial.println( stepPosition );
while (true);
}
7
// For RAMPS 1.4
#define X_DIR_PIN 55
#define X_STEP_PIN 54
#define X_ENABLE_PIN 38
#define Y_DIR_PIN 61
#define Y_STEP_PIN 60
#define Y_ENABLE_PIN 56
#define Z_DIR_PIN 48
#define Z_STEP_PIN 46
#define Z_ENABLE_PIN 62
#define A_DIR_PIN 28
#define A_STEP_PIN 26
#define A_ENABLE_PIN 24
#define B_DIR_PIN 34
#define B_STEP_PIN 36
#define B_ENABLE_PIN 30
#define C_DIR_PIN 32
#define C_STEP_PIN 47
#define C_ENABLE_PIN 45
#define X_STEP_HIGH PORTF |= 0b00000001;
#define X_STEP_LOW PORTF &= ~0b00000001;
#define Y_STEP_HIGH PORTF |= 0b01000000;
#define Y_STEP_LOW PORTF &= ~0b01000000;
#define Z_STEP_HIGH PORTL |= 0b00001000;
#define Z_STEP_LOW PORTL &= ~0b00001000;
#define A_STEP_HIGH PORTA |= 0b00010000;
#define A_STEP_LOW PORTA &= ~0b00010000;
#define B_STEP_HIGH PORTC |= 0b00000010;
#define B_STEP_LOW PORTC &= ~0b00000010;
#define C_STEP_HIGH PORTL |= 0b00000100;
#define C_STEP_LOW PORTL &= ~0b00000100;
#define TIMER1_INTERRUPTS_ON TIMSK1 |= (1 << OCIE1A);
#define TIMER1_INTERRUPTS_OFF TIMSK1 &= ~(1 << OCIE1A);
struct stepperInfo {
// externally defined parameters
float acceleration;
volatile unsigned int minStepInterval; // ie. max speed, smaller is faster
void (*dirFunc)(int);
void (*stepFunc)();
// derived parameters
unsigned int c0; // step interval for first step, determines acceleration
long stepPosition; // current position of stepper (total of all movements taken so far)
// per movement variables (only changed once per movement)
volatile int dir; // current direction of movement, used to keep track of position
volatile unsigned int totalSteps; // number of steps requested for current movement
volatile bool movementDone = false; // true if the current movement has been completed (used by main program to wait for completion)
volatile unsigned int rampUpStepCount; // number of steps taken to reach either max speed, or half-way to the goal (will be zero until this number is known)
// per iteration variables (potentially changed every interrupt)
volatile unsigned int n; // index in acceleration curve, used to calculate next interval
volatile float d; // current interval length
volatile unsigned long di; // above variable truncated
volatile unsigned int stepCount; // number of steps completed in current movement
};
void xStep() {
X_STEP_HIGH
X_STEP_LOW
}
void xDir(int dir) {
digitalWrite(X_DIR_PIN, dir);
}
void yStep() {
Y_STEP_HIGH
Y_STEP_LOW
}
void yDir(int dir) {
digitalWrite(Y_DIR_PIN, dir);
}
void zStep() {
Z_STEP_HIGH
Z_STEP_LOW
}
void zDir(int dir) {
digitalWrite(Z_DIR_PIN, dir);
}
void aStep() {
A_STEP_HIGH
A_STEP_LOW
}
void aDir(int dir) {
digitalWrite(A_DIR_PIN, dir);
}
void bStep() {
B_STEP_HIGH
B_STEP_LOW
}
void bDir(int dir) {
digitalWrite(B_DIR_PIN, dir);
}
void cStep() {
C_STEP_HIGH
C_STEP_LOW
}
void cDir(int dir) {
digitalWrite(C_DIR_PIN, dir);
}
void resetStepperInfo( stepperInfo& si ) {
si.n = 0;
si.d = 0;
si.di = 0;
si.stepCount = 0;
si.rampUpStepCount = 0;
si.totalSteps = 0;
si.stepPosition = 0;
si.movementDone = false;
}
#define NUM_STEPPERS 6
volatile stepperInfo steppers[NUM_STEPPERS];
void setup() {
pinMode(X_STEP_PIN, OUTPUT);
pinMode(X_DIR_PIN, OUTPUT);
pinMode(X_ENABLE_PIN, OUTPUT);
pinMode(Y_STEP_PIN, OUTPUT);
pinMode(Y_DIR_PIN, OUTPUT);
pinMode(Y_ENABLE_PIN, OUTPUT);
pinMode(Z_STEP_PIN, OUTPUT);
pinMode(Z_DIR_PIN, OUTPUT);
pinMode(Z_ENABLE_PIN, OUTPUT);
pinMode(A_STEP_PIN, OUTPUT);
pinMode(A_DIR_PIN, OUTPUT);
pinMode(A_ENABLE_PIN, OUTPUT);
pinMode(B_STEP_PIN, OUTPUT);
pinMode(B_DIR_PIN, OUTPUT);
pinMode(B_ENABLE_PIN, OUTPUT);
pinMode(C_STEP_PIN, OUTPUT);
pinMode(C_DIR_PIN, OUTPUT);
pinMode(C_ENABLE_PIN, OUTPUT);
digitalWrite(X_ENABLE_PIN, LOW);
digitalWrite(Y_ENABLE_PIN, LOW);
digitalWrite(Z_ENABLE_PIN, LOW);
digitalWrite(A_ENABLE_PIN, LOW);
digitalWrite(B_ENABLE_PIN, LOW);
digitalWrite(C_ENABLE_PIN, LOW);
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 1000; // compare value
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= ((1 << CS11) | (1 << CS10)); // 64 prescaler
interrupts();
steppers[0].dirFunc = bDir;
steppers[0].stepFunc = bStep;
steppers[0].acceleration = 1000;
steppers[0].minStepInterval = 50;
steppers[1].dirFunc = aDir;
steppers[1].stepFunc = aStep;
steppers[1].acceleration = 4000;
steppers[1].minStepInterval = 50;
steppers[2].dirFunc = cDir;
steppers[2].stepFunc = cStep;
steppers[2].acceleration = 1000;
steppers[2].minStepInterval = 50;
steppers[3].dirFunc = xDir;
steppers[3].stepFunc = xStep;
steppers[3].acceleration = 1000;
steppers[3].minStepInterval = 250;
steppers[4].dirFunc = yDir;
steppers[4].stepFunc = yStep;
steppers[4].acceleration = 1000;
steppers[4].minStepInterval = 50;
steppers[5].dirFunc = zDir;
steppers[5].stepFunc = zStep;
steppers[5].acceleration = 1000;
steppers[5].minStepInterval = 450;
}
void resetStepper(volatile stepperInfo& si) {
si.c0 = si.acceleration;
si.d = si.c0;
si.di = si.d;
si.stepCount = 0;
si.n = 0;
si.rampUpStepCount = 0;
si.movementDone = false;
}
volatile byte remainingSteppersFlag = 0;
void prepareMovement(int whichMotor, int steps) {
volatile stepperInfo& si = steppers[whichMotor];
si.dirFunc( steps < 0 ? HIGH : LOW );
si.dir = steps > 0 ? 1 : -1;
si.totalSteps = abs(steps);
resetStepper(si);
remainingSteppersFlag |= (1 << whichMotor);
}
volatile byte nextStepperFlag = 0;
volatile int ind = 0;
volatile unsigned int intervals[100];
void setNextInterruptInterval() {
bool movementComplete = true;
unsigned int mind = 999999;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ((1 << i) & remainingSteppersFlag) && steppers[i].di < mind ) {
mind = steppers[i].di;
}
}
nextStepperFlag = 0;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ! steppers[i].movementDone )
movementComplete = false;
if ( ((1 << i) & remainingSteppersFlag) && steppers[i].di == mind )
nextStepperFlag |= (1 << i);
}
if ( remainingSteppersFlag == 0 ) {
OCR1A = 65500;
}
OCR1A = mind;
}
ISR(TIMER1_COMPA_vect)
{
unsigned int tmpCtr = OCR1A;
OCR1A = 65500;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ! ((1 << i) & remainingSteppersFlag) )
continue;
if ( ! (nextStepperFlag & (1 << i)) ) {
steppers[i].di -= tmpCtr;
continue;
}
volatile stepperInfo& s = steppers[i];
if ( s.stepCount < s.totalSteps ) {
s.stepFunc();
s.stepCount++;
s.stepPosition += s.dir;
if ( s.stepCount >= s.totalSteps ) {
s.movementDone = true;
remainingSteppersFlag &= ~(1 << i);
}
}
if ( s.rampUpStepCount == 0 ) {
s.n++;
s.d = s.d - (2 * s.d) / (4 * s.n + 1);
if ( s.d <= s.minStepInterval ) {
s.d = s.minStepInterval;
s.rampUpStepCount = s.stepCount;
}
if ( s.stepCount >= s.totalSteps / 2 ) {
s.rampUpStepCount = s.stepCount;
}
}
else if ( s.stepCount >= s.totalSteps - s.rampUpStepCount ) {
s.d = (s.d * (4 * s.n + 1)) / (4 * s.n + 1 - 2);
s.n--;
}
s.di = s.d; // integer
}
setNextInterruptInterval();
TCNT1 = 0;
}
void runAndWait() {
setNextInterruptInterval();
while ( remainingSteppersFlag );
}
void loop() {
TIMER1_INTERRUPTS_ON
for (int i = 0; i < 4; i++) {
for (int k = 0; k < NUM_STEPPERS; k++) {
prepareMovement( k, 200 );
runAndWait();
}
}
for (int i = 0; i < 4; i++) {
for (int k = 0; k < NUM_STEPPERS; k++) {
prepareMovement( k, 200 );
}
runAndWait();
}
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, 400 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, -400 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, 200 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, -200 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, 600 );
runAndWait();
for (int i = 0; i < NUM_STEPPERS; i++)
prepareMovement( i, -600 );
runAndWait();
while (true);
}
8
// For RAMPS 1.4
#define X_DIR_PIN 55
#define X_STEP_PIN 54
#define X_ENABLE_PIN 38
#define Y_DIR_PIN 61
#define Y_STEP_PIN 60
#define Y_ENABLE_PIN 56
#define Z_DIR_PIN 48
#define Z_STEP_PIN 46
#define Z_ENABLE_PIN 62
#define A_DIR_PIN 28
#define A_STEP_PIN 26
#define A_ENABLE_PIN 24
#define B_DIR_PIN 34
#define B_STEP_PIN 36
#define B_ENABLE_PIN 30
#define C_DIR_PIN 32
#define C_STEP_PIN 47
#define C_ENABLE_PIN 45
#define X_STEP_HIGH PORTF |= 0b00000001;
#define X_STEP_LOW PORTF &= ~0b00000001;
#define Y_STEP_HIGH PORTF |= 0b01000000;
#define Y_STEP_LOW PORTF &= ~0b01000000;
#define Z_STEP_HIGH PORTL |= 0b00001000;
#define Z_STEP_LOW PORTL &= ~0b00001000;
#define A_STEP_HIGH PORTA |= 0b00010000;
#define A_STEP_LOW PORTA &= ~0b00010000;
#define B_STEP_HIGH PORTC |= 0b00000010;
#define B_STEP_LOW PORTC &= ~0b00000010;
#define C_STEP_HIGH PORTL |= 0b00000100;
#define C_STEP_LOW PORTL &= ~0b00000100;
#define TIMER1_INTERRUPTS_ON TIMSK1 |= (1 << OCIE1A);
#define TIMER1_INTERRUPTS_OFF TIMSK1 &= ~(1 << OCIE1A);
struct stepperInfo {
// externally defined parameters
float acceleration;
volatile unsigned long minStepInterval; // ie. max speed, smaller is faster
void (*dirFunc)(int);
void (*stepFunc)();
// derived parameters
unsigned int c0; // step interval for first step, determines acceleration
long stepPosition; // current position of stepper (total of all movements taken so far)
// per movement variables (only changed once per movement)
volatile int dir; // current direction of movement, used to keep track of position
volatile unsigned int totalSteps; // number of steps requested for current movement
volatile bool movementDone = false; // true if the current movement has been completed (used by main program to wait for completion)
volatile unsigned int rampUpStepCount; // number of steps taken to reach either max speed, or half-way to the goal (will be zero until this number is known)
volatile unsigned long estStepsToSpeed; // estimated steps required to reach max speed
volatile unsigned long estTimeForMove; // estimated time (interrupt ticks) required to complete movement
volatile unsigned long rampUpStepTime;
volatile float speedScale; // used to slow down this motor to make coordinated movement with other motors
// per iteration variables (potentially changed every interrupt)
volatile unsigned int n; // index in acceleration curve, used to calculate next interval
volatile float d; // current interval length
volatile unsigned long di; // above variable truncated
volatile unsigned int stepCount; // number of steps completed in current movement
};
void xStep() {
X_STEP_HIGH
X_STEP_LOW
}
void xDir(int dir) {
digitalWrite(X_DIR_PIN, dir);
}
void yStep() {
Y_STEP_HIGH
Y_STEP_LOW
}
void yDir(int dir) {
digitalWrite(Y_DIR_PIN, dir);
}
void zStep() {
Z_STEP_HIGH
Z_STEP_LOW
}
void zDir(int dir) {
digitalWrite(Z_DIR_PIN, dir);
}
void aStep() {
A_STEP_HIGH
A_STEP_LOW
}
void aDir(int dir) {
digitalWrite(A_DIR_PIN, dir);
}
void bStep() {
B_STEP_HIGH
B_STEP_LOW
}
void bDir(int dir) {
digitalWrite(B_DIR_PIN, dir);
}
void cStep() {
C_STEP_HIGH
C_STEP_LOW
}
void cDir(int dir) {
digitalWrite(C_DIR_PIN, dir);
}
void resetStepperInfo( stepperInfo& si ) {
si.n = 0;
si.d = 0;
si.di = 0;
si.stepCount = 0;
si.rampUpStepCount = 0;
si.rampUpStepTime = 0;
si.totalSteps = 0;
si.stepPosition = 0;
si.movementDone = false;
}
#define NUM_STEPPERS 6
volatile stepperInfo steppers[NUM_STEPPERS];
void setup() {
pinMode(X_STEP_PIN, OUTPUT);
pinMode(X_DIR_PIN, OUTPUT);
pinMode(X_ENABLE_PIN, OUTPUT);
pinMode(Y_STEP_PIN, OUTPUT);
pinMode(Y_DIR_PIN, OUTPUT);
pinMode(Y_ENABLE_PIN, OUTPUT);
pinMode(Z_STEP_PIN, OUTPUT);
pinMode(Z_DIR_PIN, OUTPUT);
pinMode(Z_ENABLE_PIN, OUTPUT);
pinMode(A_STEP_PIN, OUTPUT);
pinMode(A_DIR_PIN, OUTPUT);
pinMode(A_ENABLE_PIN, OUTPUT);
pinMode(B_STEP_PIN, OUTPUT);
pinMode(B_DIR_PIN, OUTPUT);
pinMode(B_ENABLE_PIN, OUTPUT);
pinMode(C_STEP_PIN, OUTPUT);
pinMode(C_DIR_PIN, OUTPUT);
pinMode(C_ENABLE_PIN, OUTPUT);
digitalWrite(X_ENABLE_PIN, LOW);
digitalWrite(Y_ENABLE_PIN, LOW);
digitalWrite(Z_ENABLE_PIN, LOW);
digitalWrite(A_ENABLE_PIN, LOW);
digitalWrite(B_ENABLE_PIN, LOW);
digitalWrite(C_ENABLE_PIN, LOW);
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 1000; // compare value
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= ((1 << CS11) | (1 << CS10)); // 64 prescaler
interrupts();
steppers[0].dirFunc = bDir;
steppers[0].stepFunc = bStep;
steppers[0].acceleration = 1000;
steppers[0].minStepInterval = 50;
steppers[1].dirFunc = aDir;
steppers[1].stepFunc = aStep;
steppers[1].acceleration = 1000;
steppers[1].minStepInterval = 50;
steppers[2].dirFunc = cDir;
steppers[2].stepFunc = cStep;
steppers[2].acceleration = 1000;
steppers[2].minStepInterval = 50;
steppers[3].dirFunc = xDir;
steppers[3].stepFunc = xStep;
steppers[3].acceleration = 1000;
steppers[3].minStepInterval = 50;
steppers[4].dirFunc = yDir;
steppers[4].stepFunc = yStep;
steppers[4].acceleration = 1000;
steppers[4].minStepInterval = 50;
steppers[5].dirFunc = zDir;
steppers[5].stepFunc = zStep;
steppers[5].acceleration = 1000;
steppers[5].minStepInterval = 50;
}
void resetStepper(volatile stepperInfo& si) {
si.c0 = si.acceleration;
si.d = si.c0;
si.di = si.d;
si.stepCount = 0;
si.n = 0;
si.rampUpStepCount = 0;
si.movementDone = false;
si.speedScale = 1;
float a = si.minStepInterval / (float)si.c0;
a *= 0.676;
float m = ((a*a - 1) / (-2 * a));
float n = m * m;
si.estStepsToSpeed = n;
}
volatile byte remainingSteppersFlag = 0;
float getDurationOfAcceleration(volatile stepperInfo& s, unsigned int numSteps) {
float d = s.c0;
float totalDuration = 0;
for (unsigned int n = 1; n < numSteps; n++) {
d = d - (2 * d) / (4 * n + 1);
totalDuration += d;
}
return totalDuration;
}
void prepareMovement(int whichMotor, long steps) {
volatile stepperInfo& si = steppers[whichMotor];
si.dirFunc( steps < 0 ? HIGH : LOW );
si.dir = steps > 0 ? 1 : -1;
si.totalSteps = abs(steps);
resetStepper(si);
remainingSteppersFlag |= (1 << whichMotor);
unsigned long stepsAbs = abs(steps);
if ( (2 * si.estStepsToSpeed) < stepsAbs ) {
// there will be a period of time at full speed
unsigned long stepsAtFullSpeed = stepsAbs - 2 * si.estStepsToSpeed;
float accelDecelTime = getDurationOfAcceleration(si, si.estStepsToSpeed);
si.estTimeForMove = 2 * accelDecelTime + stepsAtFullSpeed * si.minStepInterval;
}
else {
// will not reach full speed before needing to slow down again
float accelDecelTime = getDurationOfAcceleration( si, stepsAbs / 2 );
si.estTimeForMove = 2 * accelDecelTime;
}
}
volatile byte nextStepperFlag = 0;
void setNextInterruptInterval() {
bool movementComplete = true;
unsigned long mind = 999999;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ((1 << i) & remainingSteppersFlag) && steppers[i].di < mind ) {
mind = steppers[i].di;
}
}
nextStepperFlag = 0;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ! steppers[i].movementDone )
movementComplete = false;
if ( ((1 << i) & remainingSteppersFlag) && steppers[i].di == mind )
nextStepperFlag |= (1 << i);
}
if ( remainingSteppersFlag == 0 ) {
TIMER1_INTERRUPTS_OFF
OCR1A = 65500;
}
OCR1A = mind;
}
ISR(TIMER1_COMPA_vect)
{
unsigned int tmpCtr = OCR1A;
OCR1A = 65500;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ! ((1 << i) & remainingSteppersFlag) )
continue;
if ( ! (nextStepperFlag & (1 << i)) ) {
steppers[i].di -= tmpCtr;
continue;
}
volatile stepperInfo& s = steppers[i];
if ( s.stepCount < s.totalSteps ) {
s.stepFunc();
s.stepCount++;
s.stepPosition += s.dir;
if ( s.stepCount >= s.totalSteps ) {
s.movementDone = true;
remainingSteppersFlag &= ~(1 << i);
}
}
if ( s.rampUpStepCount == 0 ) {
s.n++;
s.d = s.d - (2 * s.d) / (4 * s.n + 1);
if ( s.d <= s.minStepInterval ) {
s.d = s.minStepInterval;
s.rampUpStepCount = s.stepCount;
}
if ( s.stepCount >= s.totalSteps / 2 ) {
s.rampUpStepCount = s.stepCount;
}
s.rampUpStepTime += s.d;
}
else if ( s.stepCount >= s.totalSteps - s.rampUpStepCount ) {
s.d = (s.d * (4 * s.n + 1)) / (4 * s.n + 1 - 2);
s.n--;
}
s.di = s.d * s.speedScale; // integer
}
setNextInterruptInterval();
TCNT1 = 0;
}
void runAndWait() {
adjustSpeedScales();
setNextInterruptInterval();
TIMER1_INTERRUPTS_ON
while ( remainingSteppersFlag );
remainingSteppersFlag = 0;
nextStepperFlag = 0;
}
void adjustSpeedScales() {
float maxTime = 0;
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ! ((1 << i) & remainingSteppersFlag) )
continue;
if ( steppers[i].estTimeForMove > maxTime )
maxTime = steppers[i].estTimeForMove;
}
if ( maxTime != 0 ) {
for (int i = 0; i < NUM_STEPPERS; i++) {
if ( ! ( (1 << i) & remainingSteppersFlag) )
continue;
steppers[i].speedScale = maxTime / steppers[i].estTimeForMove;
}
}
}
void loop() {
for (int i = 0; i < NUM_STEPPERS; i++) {
prepareMovement( i, 800 );
runAndWait();
}
prepareMovement( 0, 8000 );
prepareMovement( 1, 800 );
prepareMovement( 2, 2400 );
prepareMovement( 3, 800 );
prepareMovement( 4, 1600 );
prepareMovement( 5, 800 );
runAndWait();
delay(1000);
prepareMovement( 0, -8000 );
prepareMovement( 1, 1600 );
prepareMovement( 2, -2400 );
prepareMovement( 3, -800 );
prepareMovement( 4, 2400 );
prepareMovement( 5, -800 );
runAndWait();
while (true);
}