This repository has been archived on 2025-02-01. You can view files and clone it, but cannot push or open issues or pull requests.
reprapfirmware-dc42/Move.ino
Adrian Bowyer 82efa28c81 First crude hack at acceleration code. Timer claims that the interrupt
routine executes in 6.5 microseconds, so we shouldn't have any trouble
driving the steppers fast...
2013-05-21 21:22:12 +01:00

257 lines
5.9 KiB
C++

/****************************************************************************************************
RepRapFirmware - Move
This is all the code to deal with movement and kinematics.
-----------------------------------------------------------------------------------------------------
Version 0.1
18 November 2012
Adrian Bowyer
RepRap Professional Ltd
http://reprappro.com
Licence: GPL
****************************************************************************************************/
#include "RepRapFirmware.h"
Move::Move(Platform* p, GCodes* g)
{
active = false;
platform = p;
gCodes = g;
dda = new DDA(this, platform);
}
void Move::Init()
{
char i;
for(i = 0; i < DRIVES; i++)
platform->SetDirection(i, FORWARDS);
for(i = 0; i <= AXES; i++)
currentPosition[i] = 0.0;
lastTime = platform->Time();
currentFeedrate = START_FEED_RATE;
float dx = 1.0/platform->DriveStepsPerUnit(X_AXIS);
float dy = 1.0/platform->DriveStepsPerUnit(Y_AXIS);
float dz = 1.0/platform->DriveStepsPerUnit(Z_AXIS);
stepDistances[0] = dx; // Should never be used. Wrong, but safer than 0.0...
stepDistances[1] = dx;
stepDistances[2] = dy;
stepDistances[3] = sqrt(dx*dx + dy*dy);
stepDistances[4] = dz;
stepDistances[5] = sqrt(dx*dx + dz*dz);
stepDistances[6] = sqrt(dy*dy + dz*dz);
stepDistances[7] = sqrt(dx*dx + dy*dy + dz*dz);
active = true;
}
void Move::Exit()
{
active = false;
}
void Move::Spin()
{
if(!active)
return;
Qmove();
}
void Move::Qmove()
{
//char scratchString[STRING_LENGTH];
if(!gCodes->ReadMove(nextMove))
return;
/* platform->Message(HOST_MESSAGE, "Move - got a move:");
for(char i = 0; i <= DRIVES; i++)
{
ftoa(scratchString, nextMove[i], 3);
platform->Message(HOST_MESSAGE, scratchString);
platform->Message(HOST_MESSAGE, ", ");
}
platform->Message(HOST_MESSAGE, "\n");*/
boolean work = dda->Init(currentPosition, nextMove);
for(char i = 0; i <= AXES; i++)
currentPosition[i] = nextMove[i];
if(work)
dda->Start(true);
}
void Move::GetCurrentState(float m[])
{
for(char i = 0; i < DRIVES; i++)
{
if(i < AXES)
m[i] = currentPosition[i];
else
m[i] = 0.0;
}
m[DRIVES] = currentFeedrate;
}
//****************************************************************************************************
DDA::DDA(Move* m, Platform* p)
{
active = false;
move = m;
platform = p;
}
boolean DDA::Init(float currentPosition[], float targetPosition[])
{
char drive;
active = false;
totalSteps = -1;
float dist = 0; // X+Y+Z
float d;
char axesMoving = 0;
for(drive = 0; drive < DRIVES; drive++)
{
if(drive < AXES)
{
d = targetPosition[drive] - currentPosition[drive];
delta[drive] = (long)(d*platform->DriveStepsPerUnit(drive)); //Absolute
dist += d*d;
} else
delta[drive] = (long)(targetPosition[drive]*platform->DriveStepsPerUnit(drive)); // Relative
if(delta[drive] >= 0)
directions[drive] = FORWARDS;
else
directions[drive] = BACKWARDS;
delta[drive] = abs(delta[drive]);
if(drive == X_AXIS && delta[drive] > 0)
axesMoving |= 1;
if(drive == Y_AXIS && delta[drive] > 0)
axesMoving |= 2;
if(drive == Z_AXIS && delta[drive] > 0)
axesMoving |= 4;
if(delta[drive] > totalSteps)
totalSteps = delta[drive];
}
if(totalSteps <= 0)
return false;
counter[0] = totalSteps/2;
for(drive = 1; drive < DRIVES; drive++)
counter[drive] = counter[0];
dist = sqrt(dist);
float acc;
if(axesMoving|4)
{
acc = platform->Acceleration(Z_AXIS);
velocity = platform->Jerk(Z_AXIS);
} else
{
acc = platform->Acceleration(X_AXIS);
velocity = platform->Jerk(X_AXIS);
}
timeStep = move->stepDistances[1]/velocity;
d = 0.5*(targetPosition[DRIVES]*targetPosition[DRIVES] - velocity*velocity)/acc; // d = (v^2 - u^2)/2a
stopAStep = (long)((d*totalSteps)/dist);
startDStep = totalSteps - stopAStep;
if(stopAStep > startDStep)
{
stopAStep = totalSteps/2;
startDStep = stopAStep + 1;
}
stepCount = 0;
return true;
}
void DDA::Start(boolean noTest)
{
for(char drive = 0; drive < DRIVES; drive++)
platform->SetDirection(drive, directions[drive]);
if(noTest)
platform->SetInterrupt((long)(1.0e6*timeStep));
active = true;
}
void DDA::Step(boolean noTest)
{
if(!active && noTest)
return;
char axesMoving = 0;
counter[X_AXIS] += delta[X_AXIS];
if(counter[X_AXIS] > 0)
{
if(noTest)
platform->Step(X_AXIS);
axesMoving |= 1;
counter[X_AXIS] -= totalSteps;
}
counter[Y_AXIS] += delta[Y_AXIS];
if(counter[Y_AXIS] > 0)
{
if(noTest)
platform->Step(Y_AXIS);
axesMoving |= 2;
counter[Y_AXIS] -= totalSteps;
}
counter[Z_AXIS] += delta[Z_AXIS];
if(counter[Z_AXIS] > 0)
{
if(noTest)
platform->Step(Z_AXIS);
axesMoving |= 4;
counter[Z_AXIS] -= totalSteps;
}
for(char drive = AXES; drive < DRIVES; drive++)
{
counter[drive] += delta[drive];
if(counter[drive] > 0)
{
if(noTest)
platform->Step(drive);
counter[drive] -= totalSteps;
}
}
if(axesMoving)
{
if(stepCount < stopAStep)
{
timeStep = move->stepDistances[axesMoving]/velocity;
if(axesMoving & 4)
velocity += platform->Acceleration(Z_AXIS)*timeStep;
else
velocity += platform->Acceleration(X_AXIS)*timeStep;
if(noTest)
platform->SetInterrupt((long)(1.0e6*timeStep));
}
if(stepCount >= startDStep)
{
timeStep = move->stepDistances[axesMoving]/velocity;
if(axesMoving & 4)
velocity -= platform->Acceleration(Z_AXIS)*timeStep;
else
velocity -= platform->Acceleration(X_AXIS)*timeStep;
if(noTest)
platform->SetInterrupt((long)(1.0e6*timeStep));
}
}
stepCount++;
active = stepCount < totalSteps;
if(!active && noTest)
platform->SetInterrupt(-1);
}