This version is broken. But it is better! Major rewrite of the Move class. Now to debug it...

This commit is contained in:
Adrian Bowyer 2013-06-04 15:25:28 +01:00
parent a5c2b5b80e
commit 1e35269a06
12 changed files with 535 additions and 216 deletions

View file

@ -32,36 +32,9 @@ Licence: GPL
#define INCH_TO_MM 25.4
#define FLASH_LED 'F' // Type byte of a message that is to flash an LED; the next two bytes define
// the frequency and M/S ratio.
#define DISPLAY_MESSAGE 'L' // Type byte of a message that is to appear on a local display; the L is
// not displayed; \f and \n should be supported.
#define HOST_MESSAGE 'H' // Type byte of a message that is to be sent to the host; the H is not sent.
// Webserver stuff
#define DEFAULT_PASSWORD "reprap"
#define DEFAULT_NAME "My RepRap 1"
#define CLIENT_CLOSE_DELAY 1000 // Microseconds to wait after serving a page
#define INDEX_PAGE "reprap.htm"
#define MESSAGE_FILE "messages.txt"
#define FOUR04_FILE "html404.htm"
#define KO_START "rr_"
#define KO_FIRST 3
#define STRING_LENGTH 1000
#define POST_LENGTH 200
#define START_FEED_RATE 200.0
#define GCODE_LENGTH 100 // Maximum lenght of internally-generated G Code string
// Movement stuff
#define RING_LENGTH 10
#define LOOK_AHEAD_LENGTH 25
#define LOOK_AHEAD_FLUSH 5
#define LOOK_AHEAD_FUTURE 15
#endif

View file

@ -22,6 +22,7 @@ Licence: GPL
#ifndef GCODES_H
#define GCODES_H
// Small class to hold an individual GCode
class GCodeBuffer
@ -40,7 +41,8 @@ class GCodeBuffer
Platform* platform;
char gcodeBuffer[GCODE_LENGTH];
int gcodePointer;
int readPointer;
int readPointer;
boolean inComment;
};
//****************************************************************************************************
@ -55,7 +57,7 @@ class GCodes
void Spin();
void Init();
void Exit();
boolean ReadMove(float* m);
boolean ReadMove(float* m, boolean& ce);
boolean ReadHeat(float* h);
void QueueFileToPrint(char* fileName);
boolean PrintingAFile();
@ -65,6 +67,7 @@ class GCodes
boolean ActOnGcode(GCodeBuffer* gb);
boolean SetUpMove(GCodeBuffer* gb);
boolean DoDwell(GCodeBuffer *gb);
boolean DoHome();
Platform* platform;
boolean active;
Webserver* webserver;
@ -77,6 +80,7 @@ class GCodes
boolean moveAvailable;
boolean heatAvailable;
float moveBuffer[DRIVES+1]; // Last is feedrate
boolean checkEndStops;
boolean drivesRelative; // All except X, Y and Z
boolean axesRelative; // X, Y and Z
char gCodeLetters[DRIVES + 1]; // Extra is for F
@ -84,6 +88,7 @@ class GCodes
float distanceScale;
int fileBeingPrinted;
int fileToPrint;
char homeToDo;
};
//*****************************************************************************************************

View file

@ -46,12 +46,14 @@ void GCodes::Init()
heatAvailable = false;
drivesRelative = true;
axesRelative = false;
checkEndStops = false;
gCodeLetters = GCODE_LETTERS;
distanceScale = 1.0;
for(char i = 0; i < DRIVES - AXES; i++)
lastPos[i] = 0.0;
fileBeingPrinted = -1;
fileToPrint = -1;
homeToDo = 0;
dwellWaiting = false;
dwellTime = platform->Time();
}
@ -154,6 +156,42 @@ boolean GCodes::SetUpMove(GCodeBuffer *gb)
return true;
}
boolean GCodes::DoHome()
{
// Treat more or less like any other move
// Last one gone yet?
if(moveAvailable)
return false;
// Wait for all the queued moves to stop
if(!reprap.GetMove()->AllMovesAreFinished())
return false;
reprap.GetMove()->ResumeMoving();
// Load the last position; If Move can't accept more, return false
if(!reprap.GetMove()->GetCurrentState(moveBuffer))
return false;
for(char i = 0; i < AXES; i++)
{
if(homeToDo & 1<<i)
{
moveBuffer[i] = -2.0*platform->AxisLength(i);
moveBuffer[DRIVES] = platform->HomeFeedRate(i)/60.0;
homeToDo &= ~(1<<i);
break;
}
}
moveAvailable = true;
return homeToDo == 0;
}
void GCodes::QueueFileToPrint(char* fileName)
{
fileToPrint = platform->OpenFile(platform->GetGCodeDir(), fileName, false);
@ -233,7 +271,17 @@ boolean GCodes::ActOnGcode(GCodeBuffer *gb)
break;
case 28: // Home
platform->Message(HOST_MESSAGE, "Home received\n");
if(homeToDo == 0)
{
for(char i = 0; i < AXES; i++)
{
if(gb->Seen(gCodeLetters[i]))
homeToDo |= 1<<i;
}
if(homeToDo == 0)
homeToDo = 7;
}
result = DoHome();
break;
case 90: // Absolute coordinates
@ -353,12 +401,13 @@ boolean GCodes::ActOnGcode(GCodeBuffer *gb)
boolean GCodes::ReadMove(float* m)
boolean GCodes::ReadMove(float* m, boolean& ce)
{
if(!moveAvailable)
return false;
for(char i = 0; i <= DRIVES; i++) // 1 more for F
m[i] = moveBuffer[i];
ce = checkEndStops;
moveAvailable = false;
}
@ -377,8 +426,9 @@ GCodeBuffer::GCodeBuffer(Platform* p)
void GCodeBuffer::Init()
{
gcodePointer = 0;
readPointer = -1;
gcodePointer = 0;
readPointer = -1;
inComment = false;
}
boolean GCodeBuffer::Put(char c)
@ -386,13 +436,20 @@ boolean GCodeBuffer::Put(char c)
boolean result = false;
gcodeBuffer[gcodePointer] = c;
if(gcodeBuffer[gcodePointer] == '\n' || !gcodeBuffer[gcodePointer])
if(c == ';')
inComment = true;
if(c == '\n' || !c)
{
gcodeBuffer[gcodePointer] = 0;
gcodePointer = 0;
Init();
result = true;
} else
gcodePointer++;
{
if(!inComment)
gcodePointer++;
}
if(gcodePointer >= GCODE_LENGTH)
{

173
Move.h
View file

@ -21,12 +21,63 @@ Licence: GPL
#ifndef MOVE_H
#define MOVE_H
#define DDA_RING_LENGTH 5
#define LOOK_AHEAD_RING_LENGTH 20
#define LOOK_AHEAD 7
enum MovementProfile
{
nothing = 0, // No movement (i.e. end-position == start).
moving = 1, // Ordinary trapezoidal-velocity-profile movement
noFlat = 2, // Triangular profile movement
change = 3 // To make this movement, the initial and final velocities must change
moving = 0, // Ordinary trapezoidal-velocity-profile movement
noFlat = 1, // Triangular profile movement
change = 2 // To make this movement, the initial and final velocities must change
};
enum MovementState
{
unprocessed = 0,
vCosineSet = 1,
upPass = 2,
complete = 4,
released = 8
};
enum MovementType
{
noMove = 0,
xyMove = 1,
zMove = 2,
eMove = 4
};
class LookAhead
{
public:
LookAhead(Move* m, Platform* p, LookAhead* n);
LookAhead* Next();
LookAhead* Previous();
void Init(float ep[], float vv, boolean ce);
float* EndPoint();
float V();
void SetV(float vv);
char Processed();
void SetProcessed(MovementState ms);
boolean CheckEndStops();
void Release();
friend class Move;
private:
Move* move;
Platform* platform;
LookAhead* next;
LookAhead* previous;
float endPoint[DRIVES+1];
float Cosine();
boolean checkEndStops;
float cosine;
float endPosition[DRIVES+1]; // Last is feedrate
float v;
char processed;
};
@ -34,7 +85,7 @@ class DDA
{
public:
DDA(Move* m, Platform* p, DDA* n);
MovementProfile Init(float currentPosition[], float targetPosition[], float& u, float& v);
MovementProfile Init(LookAhead* lookAhead, float& u, float& v);
void Start(boolean noTest);
void Step(boolean noTest);
boolean Active();
@ -46,11 +97,12 @@ class DDA
Move* move;
Platform* platform;
DDA* next;
long counter[DRIVES+1];
long delta[DRIVES+1];
boolean directions[DRIVES+1];
long counter[DRIVES];
long delta[DRIVES];
boolean directions[DRIVES];
long totalSteps;
long stepCount;
boolean checkEndStops;
float timeStep;
float velocity;
long stopAStep;
@ -58,36 +110,11 @@ class DDA
float distance;
float dCross;
float acceleration;
float jerk;
float instantDv;
volatile boolean active;
};
class LookAhead
{
public:
LookAhead(Move* m, Platform* p, LookAhead* n);
LookAhead* Next();
LookAhead* Previous();
void Init(float m[], float uu, float vv);
void SetUV(float uu, float vv);
float* Movement();
float U();
float V();
boolean Processed();
void SetProcessed();
friend class Move;
private:
Move* move;
Platform* platform;
LookAhead* next;
LookAhead* previous;
float Cosine(LookAhead* a);
float movement[DRIVES+1]; // Last is feedrate
float u, v;
boolean processed;
};
class Move
@ -103,12 +130,15 @@ class Move
void InterruptTime();
boolean AllMovesAreFinished();
void ResumeMoving();
void DoLookAhead();
void HitLowStop(char drive);
void HitHighStop(char drive);
friend class DDA;
private:
boolean DDARingAdd(float currentPosition[], float targetPosition[], float& u, float& v);
boolean DDARingAdd(LookAhead* lookAhead);
DDA* DDARingGet();
boolean DDARingEmpty();
boolean DDARingFull();
@ -116,8 +146,10 @@ class Move
void ReleaseDDARingLock();
boolean LookAheadRingEmpty();
boolean LookAheadRingFull();
boolean LookAheadRingAdd(float m[], float uu, float vv);
boolean LookAheadRingAdd(float ep[], float vv, boolean ce);
LookAhead* LookAheadRingGet();
char GetMovementType(float sp[], float ep[]);
Platform* platform;
GCodes* gCodes;
@ -137,6 +169,7 @@ class Move
boolean addNoMoreMoves;
boolean active;
boolean moveWaiting;
boolean checkEndStopsOnNextMove;
float currentFeedrate;
float currentPosition[AXES]; // Note - drives above AXES are always relative moves
float nextMove[DRIVES + 1]; // Extra is for feedrate
@ -146,16 +179,6 @@ class Move
//********************************************************************************************************
inline boolean DDA::Active()
{
return active;
}
inline DDA* DDA::Next()
{
return next;
}
inline LookAhead* LookAhead::Next()
{
return next;
@ -166,37 +189,61 @@ inline LookAhead* LookAhead::Previous()
return previous;
}
inline void LookAhead::SetUV(float uu, float vv)
inline void LookAhead::SetV(float vv)
{
u = uu;
v = vv;
}
inline float* LookAhead::Movement()
inline float* LookAhead::EndPoint()
{
return movement;
return endPoint;
}
inline float LookAhead::U()
{
return u;
}
inline float LookAhead::V()
{
return v;
}
inline boolean LookAhead::Processed()
inline char LookAhead::Processed()
{
return processed;
}
inline void LookAhead::SetProcessed()
inline void LookAhead::SetProcessed(MovementState ms)
{
processed = true;
if(ms == 0)
processed = 0;
else
processed |= ms;
}
inline void LookAhead::Release()
{
processed = released;
}
inline boolean LookAhead::CheckEndStops()
{
return checkEndStops;
}
//******************************************************************************************************
inline boolean DDA::Active()
{
return active;
}
inline DDA* DDA::Next()
{
return next;
}
//***************************************************************************************
inline boolean Move::DDARingEmpty()
{
return ddaRingGetPointer == ddaRingAddPointer;
@ -251,5 +298,15 @@ inline void Move::ResumeMoving()
addNoMoreMoves = false;
}
inline void Move::HitLowStop(char drive)
{
// Put some code here
}
inline void Move::HitHighStop(char drive)
{
// and here
}
#endif

351
Move.ino
View file

@ -31,23 +31,26 @@ Move::Move(Platform* p, GCodes* g)
ddaRingAddPointer = new DDA(this, platform, NULL);
dda = ddaRingAddPointer;
for(i = 1; i < RING_LENGTH; i++)
for(i = 1; i < DDA_RING_LENGTH; i++)
dda = new DDA(this, platform, dda);
ddaRingAddPointer->next = dda;
dda = NULL;
// Build the lookahead ring
lookAheadRingAddPointer = new LookAhead(this, platform, NULL);
lookAheadRingGetPointer = lookAheadRingAddPointer;
for(i = 1; i < RING_LENGTH; i++)
for(i = 1; i < LOOK_AHEAD_RING_LENGTH; i++)
lookAheadRingGetPointer = new LookAhead(this, platform, lookAheadRingGetPointer);
lookAheadRingAddPointer->next = lookAheadRingGetPointer;
// Set the backwards pointers
// Set the backwards pointers and flag them all as free
lookAheadRingGetPointer = lookAheadRingAddPointer;
for(i = 0; i <= RING_LENGTH; i++)
for(i = 0; i <= LOOK_AHEAD_RING_LENGTH; i++)
{
lookAheadRingAddPointer->SetProcessed(released);
lookAheadRingAddPointer = lookAheadRingAddPointer->Next();
lookAheadRingAddPointer->previous = lookAheadRingGetPointer;
lookAheadRingGetPointer = lookAheadRingAddPointer;
@ -83,13 +86,14 @@ void Move::Init()
for(i = 0; i < DRIVES; i++)
nextMove[i] = 0.0;
nextMove[DRIVES] = currentFeedrate;
LookAheadRingAdd(nextMove, 0.0, 0.0);
checkEndStopsOnNextMove = false;
LookAheadRingAdd(nextMove, 0.0, false);
// Now remove it from the ring; it will remain as what is now the
// previous move, so the first real move will see that as
// the place to move from.
// the place to move from. Flag it as fully processed.
LookAheadRingGet();
LookAheadRingGet()->SetProcessed(released);
// The stepDistances arrays are look-up tables of the Euclidean distance
// between the start and end of a step. If the step is just along one axis,
@ -149,15 +153,15 @@ void Move::Spin()
if(!active)
return;
DoLookAhead();
//FIXME
float u = 0.0; // This will provoke the code to select the jerk values.
float u = 0.0; // This will provoke the code to select the instantDv values.
float v = 0.0;
if(larWaiting != NULL)
{
u = larWaiting->U();
v = larWaiting->V();
if(DDARingAdd(larWaiting->Previous()->Movement(), larWaiting->Movement(), u, v))
if(DDARingAdd(larWaiting))
larWaiting = NULL;
} else
{
@ -169,7 +173,7 @@ void Move::Spin()
{
if(!addNoMoreMoves)
{
if(LookAheadRingAdd(nextMove, u, v))
if(LookAheadRingAdd(nextMove, v, checkEndStopsOnNextMove))
{
for(char i = 0; i < AXES; i++)
currentPosition[i] = nextMove[i];
@ -179,13 +183,21 @@ void Move::Spin()
}
} else
{
moveWaiting = gCodes->ReadMove(nextMove);
moveWaiting = gCodes->ReadMove(nextMove, checkEndStopsOnNextMove);
if(moveWaiting)
{
if(GetMovementType(currentPosition, nextMove) == noMove)
{
currentFeedrate = nextMove[DRIVES]; // Might be G1 with just an F field
moveWaiting = false; // Throw it away
}
}
}
}
boolean Move::GetCurrentState(float m[])
{
if(DDARingFull())
if(LookAheadRingFull())
return false;
for(char i = 0; i < DRIVES; i++)
@ -199,8 +211,31 @@ boolean Move::GetCurrentState(float m[])
return true;
}
char Move::GetMovementType(float p0[], float p1[])
{
char result = noMove;
for(char drive = 0; drive < DRIVES; drive++)
{
if(drive < AXES)
{
if( (long)roundf((p1[drive] - p0[drive])*platform->DriveStepsPerUnit(drive)) )
{
if(drive == Z_AXIS)
result |= zMove;
else
result |= xyMove;
}
} else
{
if( (long)roundf(p1[drive]*platform->DriveStepsPerUnit(drive)) )
result |= eMove;
}
}
return result;
}
boolean Move::DDARingAdd(float currentPosition[], float targetPosition[], float& u, float& v)
boolean Move::DDARingAdd(LookAhead* lookAhead)
{
if(GetDDARingLock())
{
@ -211,16 +246,16 @@ boolean Move::DDARingAdd(float currentPosition[], float targetPosition[], float&
}
if(ddaRingAddPointer->Active())
{
platform->Message(HOST_MESSAGE, "Attempt to alter an active ring buffer entry!\n");
platform->Message(HOST_MESSAGE, "Attempt to alter an active ring buffer entry!\n"); // Should never happen...
ReleaseDDARingLock();
return false;
}
if(ddaRingAddPointer->Init(currentPosition, targetPosition, u, v) == nothing)
{
// Throw it away
ReleaseDDARingLock();
return true;
}
// We don't care about Init()'s return value - that should all have been sorted
// out by LookAhead.
float u, v;
ddaRingAddPointer->Init(lookAhead, u, v);
ddaRingAddPointer = ddaRingAddPointer->Next();
ReleaseDDARingLock();
return true;
@ -248,6 +283,74 @@ DDA* Move::DDARingGet()
}
void Move::DoLookAhead()
{
if(LookAheadRingEmpty())
return;
LookAhead* n0;
LookAhead* n1;
LookAhead* n2;
float u, v;
// if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount >= LOOK_AHEAD)
// {
/* n2 = lookAheadRingAddPointer->Previous();
n1 = n2->Previous();
n0 = n1->Previous();
while(n1 != lookAheadRingGetPointer)
{
if(n1->Processed() & vCosineSet)
{
u = n0->V();
v = n1->V();
if(lookAheadDDA->Init(n0->EndPosition(), n1->EndPosition(), u, v) & change)
{
n0->SetV(u);
n1->SetV(v);
}
}
n2 = n1;
n1 = n0;
n0 = n0->Previous();
}
}*/
n1 = lookAheadRingGetPointer;
n0 = n1->Previous();
n2 = n1->Next();
while(n2 != lookAheadRingAddPointer)
{
if(n1->Processed() == unprocessed)
{
float c = n1->Cosine();
c = n1->EndPoint()[DRIVES]*c;
if(c <= 0)
{
char mt = GetMovementType(n0->EndPoint(), n1->EndPoint());
if(mt & zMove)
c = platform->InstantDv(Z_AXIS);
else if (mt & xyMove)
c = platform->InstantDv(X_AXIS);
else
c = platform->InstantDv(AXES); // value for first extruder - slight hack
}
Serial.print("End V: ");
Serial.println(c);
n1->SetV(c);
//n1->SetProcessed(vCosineSet);
n1->SetProcessed(complete);
}
n0 = n1;
n1 = n2;
n2 = n2->Next();
}
n1->SetProcessed(complete);
//}
}
void Move::Interrupt()
{
// Have we got a live DDA?
@ -273,18 +376,16 @@ void Move::Interrupt()
}
// Yes - it's finished. Throw it away so the code above will then find a new one.
// (N.B. This is not a memory leak. The DDAs are stored in the ring buffer, initialised
// on boot, and never renewed or overwritten. dda is just a copied pointer.)
dda = NULL;
}
boolean Move::LookAheadRingAdd(float m[], float uu, float vv)
boolean Move::LookAheadRingAdd(float ep[], float vv, boolean ce)
{
if(LookAheadRingFull())
return false;
lookAheadRingAddPointer->Init(m, uu, vv);
lookAheadRingAddPointer->Init(ep, vv, ce);
lookAheadRingAddPointer = lookAheadRingAddPointer->Next();
lookAheadRingCount++;
return true;
@ -297,7 +398,7 @@ LookAhead* Move::LookAheadRingGet()
if(LookAheadRingEmpty())
return NULL;
result = lookAheadRingGetPointer;
if(!result->Processed())
if(!(result->Processed() & released))
return NULL;
lookAheadRingGetPointer = lookAheadRingGetPointer->Next();
lookAheadRingCount--;
@ -305,13 +406,14 @@ LookAhead* Move::LookAheadRingGet()
}
// FIXME
// This function is never normally called. It is a test to time
// the interrupt function. To activate it, uncomment the line that calls
// this in Platform.ino.
void Move::InterruptTime()
{
char buffer[50];
/* char buffer[50];
float a[] = {1.0, 2.0, 3.0, 4.0, 5.0};
float b[] = {2.0, 3.0, 4.0, 5.0, 6.0};
float u = 50;
@ -325,7 +427,7 @@ void Move::InterruptTime()
platform->Message(HOST_MESSAGE, "Time for 100000 calls of the interrupt function: ");
sprintf(buffer, "%ld", t);
platform->Message(HOST_MESSAGE, buffer);
platform->Message(HOST_MESSAGE, " microseconds.\n");
platform->Message(HOST_MESSAGE, " microseconds.\n");*/
}
//****************************************************************************************************
@ -352,11 +454,12 @@ u and v cannot be satisfied with the distance available and reduces them
proportionately to give values that can just be achieved, which is why they
are passed by reference.
The return value is true for an actual move, false for a zero-length (i.e. null) move.
The return value is indicates if the move is a trapezium or triangle, and if
the u and u values need to be changed.
Every drive has an acceleration associated with it, so when more than one drive is
moving there have to be rules of precedence that say which acceleration (and which
jerk value) to use.
instantDv value) to use.
The rules are these:
@ -368,7 +471,7 @@ The rules are these:
Use the acceleration for the extruder that's moving.
In the case of multiple extruders moving at once, their minimum acceleration (and its
associated jerk) are used. The variables axesMoving and extrudersMoving track what's
associated instantDv) are used. The variables axesMoving and extrudersMoving track what's
going on. The bits in the char axesMoving are ORed:
msb -> 00000ZYX <- lsb
@ -386,17 +489,20 @@ TODO: Worry about having more than eight extruders...
*/
MovementProfile DDA::Init(float currentPosition[], float targetPosition[], float& u, float& v)
MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
{
char drive;
active = false;
MovementProfile result = nothing;
MovementProfile result = moving;
totalSteps = -1;
distance = 0.0; // X+Y+Z
float eDistance = 0.0;
float d;
unsigned char axesMoving = 0;
unsigned char extrudersMoving = 0;
float* targetPosition = lookAhead->EndPoint();
v = lookAhead->V();
float* currentPosition = lookAhead->Previous()->EndPoint();
u = lookAhead->Previous()->V();
checkEndStops = lookAhead->CheckEndStops();
// How far are we going, both in steps and in mm?
@ -406,15 +512,11 @@ MovementProfile DDA::Init(float currentPosition[], float targetPosition[], float
{
d = targetPosition[drive] - currentPosition[drive]; //Absolute
distance += d*d;
delta[drive] = (long)(d*platform->DriveStepsPerUnit(drive));
if(delta[drive])
axesMoving |= 1<<drive;
delta[drive] = (long)roundf(d*platform->DriveStepsPerUnit(drive));
} else
{
delta[drive] = (long)(targetPosition[drive]*platform->DriveStepsPerUnit(drive)); // Relative
delta[drive] = (long)roundf(targetPosition[drive]*platform->DriveStepsPerUnit(drive)); // Relative
eDistance += targetPosition[drive]*targetPosition[drive];
if(delta[drive])
extrudersMoving |= 1<<(drive - AXES);
}
if(delta[drive] >= 0)
@ -429,10 +531,13 @@ MovementProfile DDA::Init(float currentPosition[], float targetPosition[], float
totalSteps = delta[drive];
}
// Not going anywhere?
// Not going anywhere? Should have been chucked away before we got here.
if(totalSteps <= 0)
{
platform->Message(HOST_MESSAGE, "DDA.Init(): Null movement!\n");
return result;
}
// Set up the DDA
@ -446,48 +551,56 @@ MovementProfile DDA::Init(float currentPosition[], float targetPosition[], float
distance = sqrt(distance);
if(axesMoving & (1<<Z_AXIS)) // Z involved?
// Decide the appropriate acceleration and instantDv values
// timeStep is set here to the distance of the
// corresponding axis step. It will be divided
// by a velocity later.
if(delta[Z_AXIS]) // Z involved?
{
acceleration = platform->Acceleration(Z_AXIS);
jerk = platform->Jerk(Z_AXIS);
} else if(axesMoving) // X or Y involved?
instantDv = platform->InstantDv(Z_AXIS);
timeStep = 1.0/platform->DriveStepsPerUnit(Z_AXIS);
} else if(delta[X_AXIS] || delta[Y_AXIS]) // X or Y involved?
{
acceleration = platform->Acceleration(X_AXIS);
jerk = platform->Jerk(X_AXIS);
instantDv = platform->InstantDv(X_AXIS);
timeStep = 1.0/platform->DriveStepsPerUnit(X_AXIS); // Slight hack
} else // Must be extruders only
{
acceleration = FLT_MAX; // Slight hack
distance = sqrt(eDistance);
for(drive = AXES; drive < DRIVES; drive++)
{
if(extrudersMoving & (1<<(drive - AXES)))
if(delta[drive])
{
if(platform->Acceleration(drive) < acceleration)
{
acceleration = platform->Acceleration(drive);
jerk = platform->Jerk(drive);
instantDv = platform->InstantDv(drive);
timeStep = 1.0/platform->DriveStepsPerUnit(drive);
}
}
}
}
// If velocities requested are (almost) zero, set them to the jerk
// If velocities requested are (almost) zero, set them to instantDv
if(v < 0.01) // Set change here?
v = jerk;
v = instantDv;
if(u < 0.01)
u = jerk;
u = instantDv;
// At which DDA step should we stop accelerating? targetPosition[DRIVES] contains
// the desired feedrate.
d = 0.5*(targetPosition[DRIVES]*targetPosition[DRIVES] - u*u)/acceleration; // d = (v1^2 - v0^2)/2a
stopAStep = (long)((d*totalSteps)/distance);
stopAStep = (long)roundf((d*totalSteps)/distance);
// At which DDA step should we start decelerating?
d = 0.5*(v*v - targetPosition[DRIVES]*targetPosition[DRIVES])/acceleration; // This should be 0 or negative...
startDStep = totalSteps + (long)((d*totalSteps)/distance);
startDStep = totalSteps + (long)roundf((d*totalSteps)/distance);
// If acceleration stop is at or after deceleration start, then the distance moved
// is not enough to get to full speed.
@ -542,18 +655,19 @@ MovementProfile DDA::Init(float currentPosition[], float targetPosition[], float
if(velocity <= 0.0)
{
velocity = 1.0;
platform->Message(HOST_MESSAGE, "DDA.Init(): Zero or negative initial velocity!");
platform->Message(HOST_MESSAGE, "DDA.Init(): Zero or negative initial velocity!\n");
}
// How far have we gone?
stepCount = 0;
// Guess that the first DDA move will be in roughly the direction
// recorded in axesMoving. This is a simple heuristic, and any
// small error will be forgotten with the very next step.
// timeStep is an axis step distance at this point; divide it by the
// velocity to get time.
timeStep = move->stepDistances[axesMoving]/velocity;
timeStep = timeStep/velocity;
lookAhead->Release();
return result;
}
@ -563,7 +677,7 @@ 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));
platform->SetInterrupt((long)(1.0e6*timeStep)); // microseconds
active = true;
}
@ -581,7 +695,26 @@ void DDA::Step(boolean noTest)
if(counter[drive] > 0)
{
if(noTest)
{
platform->Step(drive);
// Hit anything?
if(checkEndStops)
{
EndStopHit esh = platform->Stopped(drive);
if(esh == lowHit)
{
move->HitLowStop(drive);
active = false;
}
if(esh == highHit)
{
move->HitHighStop(drive);
active = false;
}
}
}
counter[drive] -= totalSteps;
if(drive < AXES)
@ -591,34 +724,39 @@ void DDA::Step(boolean noTest)
}
}
// Simple Euler integration to get velocities.
// Maybe one day do a Runge-Kutta?
// May have hit a stop
if(stepCount < stopAStep)
if(active)
{
if(axesMoving)
timeStep = move->stepDistances[axesMoving]/velocity;
else
timeStep = move->extruderStepDistances[extrudersMoving]/velocity;
velocity += acceleration*timeStep;
if(noTest)
// Simple Euler integration to get velocities.
// Maybe one day do a Runge-Kutta?
if(stepCount < stopAStep)
{
if(axesMoving)
timeStep = move->stepDistances[axesMoving]/velocity;
else
timeStep = move->extruderStepDistances[extrudersMoving]/velocity;
velocity += acceleration*timeStep;
if(noTest)
platform->SetInterrupt((long)(1.0e6*timeStep));
}
if(stepCount >= startDStep)
{
if(axesMoving)
timeStep = move->stepDistances[axesMoving]/velocity;
else
timeStep = move->extruderStepDistances[extrudersMoving]/velocity;
velocity -= acceleration*timeStep;
if(noTest)
platform->SetInterrupt((long)(1.0e6*timeStep));
}
stepCount++;
active = stepCount < totalSteps;
}
if(stepCount >= startDStep)
{
if(axesMoving)
timeStep = move->stepDistances[axesMoving]/velocity;
else
timeStep = move->extruderStepDistances[extrudersMoving]/velocity;
velocity -= acceleration*timeStep;
if(noTest)
platform->SetInterrupt((long)(1.0e6*timeStep));
}
stepCount++;
active = stepCount < totalSteps;
if(!active && noTest)
platform->SetInterrupt(STANDBY_INTERRUPT_RATE);
}
@ -632,40 +770,55 @@ LookAhead::LookAhead(Move* m, Platform* p, LookAhead* n)
next = n;
}
void LookAhead::Init(float m[], float uu, float vv)
void LookAhead::Init(float ep[], float vv, boolean ce)
{
u = uu;
v = vv;
processed = true; // Fixme
for(char i = 0; i <= DRIVES; i++)
movement[i] = m[i];
endPoint[i] = ep[i];
checkEndStops = ce;
// Cosines are lazily evaluated; flag this
// as unevaluated
cosine = 2.0;
// Only bother with lookahead when we
// are printing a file, so set processed
// complete when we aren't.
if(reprap.GetGCodes()->PrintingAFile())
processed = unprocessed;
else
processed = complete|vCosineSet|upPass;
}
// This returns the cosine of the angle between
// the movement starting at start, and the movement
// starting at the end of that. Note that it
// the movement up to this, and the movement
// away from this. Note that it
// includes Z movements, though Z values will almost always
// not change.
// not change. Uses lazy evaluation.
float LookAhead::Cosine(LookAhead* start)
float LookAhead::Cosine()
{
LookAhead* n1 = start->Next();
LookAhead* n2 = n1->Next();
float sum = 0.0;
if(cosine < 1.5)
return cosine;
cosine = 0.0;
float a2 = 0.0;
float b2 = 0.0;
float m1;
float m2;
for(char i = 0; i < AXES; i++)
{
m1 = n1->movement[i] - start->movement[i];
m2 = n2->movement[i] - n1->movement[i];
m1 = endPosition[i] - Previous()->endPosition[i];
m2 = Next()->endPosition[i] - endPosition[i];
a2 += m1*m1;
b2 += m2*m2;
sum += m1*m2;
cosine += m1*m2;
}
sum = sum/( (float)sqrt(a2) * (float)sqrt(b2) );
return sum;
cosine = cosine/( (float)sqrt(a2) * (float)sqrt(b2) );
return cosine;
}

View file

@ -44,6 +44,14 @@ Licence: GPL
#include <Arduino.h>
/**************************************************************************************************/
// Some numbers...
#define CLIENT_CLOSE_DELAY 1000 // Microseconds to wait after serving a page
#define STRING_LENGTH 1000
/**************************************************************************************************/
// The physical capabilities of the machine
@ -69,15 +77,18 @@ Licence: GPL
#define HIGH_STOP_PINS {-1, -1, -1, -1}
#define ENDSTOP_HIT 1 // when a stop == this it is hit
#define MAX_FEEDRATES {300, 300, 3, 45} // mm/sec
#define ACCELERATIONS {800, 800, 30, 250} // mm/sec^2??
//#define ACCELERATIONS {800, 800, 30, 250} // mm/sec^2??
#define ACCELERATIONS {80, 80, 3, 25}
#define DRIVE_STEPS_PER_UNIT {91.4286, 91.4286, 4000, 929}
#define JERKS {15.0, 15.0, 0.4, 15.0} // (mm/sec)
#define INSTANT_DVS {15.0, 15.0, 0.4, 15.0} // (mm/sec)
#define GCODE_LETTERS { 'X', 'Y', 'Z', 'E', 'F' } // The drives and feedrate in a GCode
// AXES
#define START_FEED_RATE 200.0
#define AXIS_LENGTHS {210, 210, 120} // mm
#define FAST_HOME_FEEDRATES {50*60, 50*60, 1*60} // mm/min
#define HOME_FEEDRATES {50*60, 50*60, 1*60} // mm/min
#define X_AXIS 0 // The index of the X axis
#define Y_AXIS 1 // The index of the Y axis
@ -117,6 +128,12 @@ Licence: GPL
#define FILE_LIST_BRACKET '"'
#define FILE_LIST_LENGTH 1000 // Maximum lenght of file list
#define FLASH_LED 'F' // Type byte of a message that is to flash an LED; the next two bytes define
// the frequency and M/S ratio.
#define DISPLAY_MESSAGE 'L' // Type byte of a message that is to appear on a local display; the L is
// not displayed; \f and \n should be supported.
#define HOST_MESSAGE 'H' // Type byte of a message that is to be sent to the host; the H is not sent.
/****************************************************************************************************/
// Networking
@ -156,6 +173,13 @@ Licence: GPL
/****************************************************************************************************/
enum EndStopHit
{
noStop = 0,
lowHit = 1,
highHit = 2
};
class Platform
{
public:
@ -213,10 +237,12 @@ class Platform
void SetDirection(byte drive, bool direction);
void Step(byte drive);
void Disable(byte drive); // There is no drive enable; drives get enabled automatically the first time they are used.
void Home(byte axis);
float DriveStepsPerUnit(char drive);
float Acceleration(char drive);
float Jerk(char drive);
float InstantDv(char drive);
float HomeFeedRate(char drive);
EndStopHit Stopped(char drive);
float AxisLength(char drive);
float ZProbe(); // Return the height above the bed. Returned value is negative if probing isn't implemented
void ZProbe(float h); // Move to height h above the bed using the probe (if there is one). h should be non-negative.
@ -257,12 +283,12 @@ class Platform
float maxFeedrates[DRIVES];
float accelerations[DRIVES];
float driveStepsPerUnit[DRIVES];
float jerks[DRIVES];
float instantDvs[DRIVES];
// AXES
float axisLengths[AXES];
float fastHomeFeedrates[AXES];
float homeFeedrates[AXES];
// HEATERS - Bed is assumed to be the first
@ -352,9 +378,9 @@ inline float Platform::Acceleration(char drive)
return accelerations[drive];
}
inline float Platform::Jerk(char drive)
inline float Platform::InstantDv(char drive)
{
return jerks[drive];
return instantDvs[drive];
}
inline void Platform::SetDirection(byte drive, bool direction)
@ -369,6 +395,31 @@ inline void Platform::Step(byte drive)
digitalWrite(stepPins[drive], 1);
}
inline float Platform::HomeFeedRate(char drive)
{
return homeFeedrates[drive];
}
inline EndStopHit Platform::Stopped(char drive)
{
if(lowStopPins[drive] >= 0)
{
if(digitalRead(lowStopPins[drive]) == ENDSTOP_HIT)
return lowHit;
}
if(highStopPins[drive] >= 0)
{
if(digitalRead(highStopPins[drive]) == ENDSTOP_HIT)
return highHit;
}
return noStop;
}
inline float Platform::AxisLength(char drive)
{
return axisLengths[drive];
}
inline int Platform::GetRawTemperature(byte heater)
{
return analogRead(tempSensePins[heater]);

View file

@ -81,12 +81,12 @@ void Platform::Init()
maxFeedrates = MAX_FEEDRATES;
accelerations = ACCELERATIONS;
driveStepsPerUnit = DRIVE_STEPS_PER_UNIT;
jerks = JERKS;
instantDvs = INSTANT_DVS;
// AXES
axisLengths = AXIS_LENGTHS;
fastHomeFeedrates = FAST_HOME_FEEDRATES;
homeFeedrates = HOME_FEEDRATES;
// HEATERS - Bed is assumed to be the first

View file

@ -1,9 +1,11 @@
G1 X55 Y5 F2000
G1 X55 Y55
G1 X5 Y55
G1 X5 Y5
G1 X55 Y5
G1 X55 Y55
G1 X5 Y55
G1 X5 Y5
G1 Y55
G1 X5
G1 Y5
G1 X30
G1 X55
G1 Y55 ; Confusing: F20
G1 Y55
G1 X5
G1 Y5

View file

@ -0,0 +1,11 @@
G1 X55 Y5 F2000
G1 Y55
G1 X5
G1 Y5
G1 X30
G1 X55
G1 Y55
G1 Y55
G1 X5
G1 Y5

View file

@ -1,7 +1,7 @@
<!DOCTYPE HTML>
<head>
<link rel="shortcut icon" href="favicon.ico" />
<link rel="shortcut icon" href="https://github.com/reprappro/RepRapFirmware/raw/due/SD-image/www/favicon.ico" />
<style type="text/css">
.pages
@ -69,8 +69,8 @@ td { text-align: center; }
</head>
<html>
<script src="jquery.js" type="text/javascript"></script>
<script src="knockout.js" type="text/javascript"></script>
<script src="https://raw.github.com/reprappro/RepRapFirmware/due/SD-image/www/jquery.js" type="text/javascript"></script>
<script src="https://raw.github.com/reprappro/RepRapFirmware/due/SD-image/www/knockout.js" type="text/javascript"></script>
<script>
function jogRowHTML(axis)
{

View file

@ -1,6 +1,8 @@
<!DOCTYPE HTML>
<head>
<link rel="shortcut icon" href="https://github.com/reprappro/RepRapFirmware/raw/due/SD-image/www/favicon.ico" />
<style type="text/css">
.pages
{
@ -67,8 +69,8 @@ td { text-align: center; }
</head>
<html>
<script src="jquery.js" type="text/javascript"></script>
<script src="knockout.js" type="text/javascript"></script>
<script src="https://raw.github.com/reprappro/RepRapFirmware/due/SD-image/www/jquery.js" type="text/javascript"></script>
<script src="https://raw.github.com/reprappro/RepRapFirmware/due/SD-image/www/knockout.js" type="text/javascript"></script>
<script>
function jogRowHTML(axis)
{

View file

@ -31,6 +31,14 @@ Licence: GPL
#define WEBSERVER_H
#define INDEX_PAGE "reprap.htm"
#define MESSAGE_FILE "messages.txt"
#define FOUR04_FILE "html404.htm"
#define KO_START "rr_"
#define KO_FIRST 3
#define POST_LENGTH 200
#define GCODE_LENGTH 100 // Maximum lenght of internally-generated G Code string
class Webserver
{
public: