Current position array removed - now all handled by the look ahead ring.
This commit is contained in:
parent
21c22a3aef
commit
db890d6157
7 changed files with 336 additions and 85 deletions
31
Move.h
31
Move.h
|
@ -77,7 +77,7 @@ class LookAhead
|
||||||
boolean checkEndStops;
|
boolean checkEndStops;
|
||||||
float cosine;
|
float cosine;
|
||||||
float v;
|
float v;
|
||||||
int8_t processed;
|
volatile int8_t processed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,6 +97,7 @@ class DDA
|
||||||
Move* move;
|
Move* move;
|
||||||
Platform* platform;
|
Platform* platform;
|
||||||
DDA* next;
|
DDA* next;
|
||||||
|
LookAhead* myLookAheadEntry;
|
||||||
long counter[DRIVES];
|
long counter[DRIVES];
|
||||||
long delta[DRIVES];
|
long delta[DRIVES];
|
||||||
boolean directions[DRIVES];
|
boolean directions[DRIVES];
|
||||||
|
@ -131,8 +132,8 @@ class Move
|
||||||
boolean AllMovesAreFinished();
|
boolean AllMovesAreFinished();
|
||||||
void ResumeMoving();
|
void ResumeMoving();
|
||||||
void DoLookAhead();
|
void DoLookAhead();
|
||||||
void HitLowStop(int8_t drive);
|
void HitLowStop(int8_t drive, LookAhead* la);
|
||||||
void HitHighStop(int8_t drive);
|
void HitHighStop(int8_t drive, LookAhead* la);
|
||||||
|
|
||||||
friend class DDA;
|
friend class DDA;
|
||||||
|
|
||||||
|
@ -162,7 +163,7 @@ class Move
|
||||||
|
|
||||||
LookAhead* lookAheadRingAddPointer;
|
LookAhead* lookAheadRingAddPointer;
|
||||||
LookAhead* lookAheadRingGetPointer;
|
LookAhead* lookAheadRingGetPointer;
|
||||||
//LookAhead* larWaiting;
|
LookAhead* lastMove;
|
||||||
DDA* lookAheadDDA;
|
DDA* lookAheadDDA;
|
||||||
int lookAheadRingCount;
|
int lookAheadRingCount;
|
||||||
|
|
||||||
|
@ -171,7 +172,6 @@ class Move
|
||||||
boolean active;
|
boolean active;
|
||||||
boolean checkEndStopsOnNextMove;
|
boolean checkEndStopsOnNextMove;
|
||||||
float currentFeedrate;
|
float currentFeedrate;
|
||||||
float currentPosition[AXES]; // Note - drives above AXES are always relative moves
|
|
||||||
float nextMove[DRIVES + 1]; // Extra is for feedrate
|
float nextMove[DRIVES + 1]; // Extra is for feedrate
|
||||||
float stepDistances[(1<<AXES)]; // Index bits: lsb -> dx, dy, dz <- msb
|
float stepDistances[(1<<AXES)]; // Index bits: lsb -> dx, dy, dz <- msb
|
||||||
float extruderStepDistances[(1<<(DRIVES-AXES))]; // NB - limits us to 5 extruders
|
float extruderStepDistances[(1<<(DRIVES-AXES))]; // NB - limits us to 5 extruders
|
||||||
|
@ -213,15 +213,15 @@ inline int8_t LookAhead::Processed()
|
||||||
|
|
||||||
inline void LookAhead::SetProcessed(MovementState ms)
|
inline void LookAhead::SetProcessed(MovementState ms)
|
||||||
{
|
{
|
||||||
if(ms == 0)
|
if(ms == unprocessed)
|
||||||
processed = 0;
|
processed = unprocessed;
|
||||||
else
|
else
|
||||||
processed |= ms;
|
processed |= ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void LookAhead::Release()
|
inline void LookAhead::Release()
|
||||||
{
|
{
|
||||||
processed = released;
|
SetProcessed(released);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline boolean LookAhead::CheckEndStops()
|
inline boolean LookAhead::CheckEndStops()
|
||||||
|
@ -232,6 +232,7 @@ inline boolean LookAhead::CheckEndStops()
|
||||||
inline void LookAhead::SetDriveZeroEndSpeed(float a, int8_t drive)
|
inline void LookAhead::SetDriveZeroEndSpeed(float a, int8_t drive)
|
||||||
{
|
{
|
||||||
endPoint[drive] = a;
|
endPoint[drive] = a;
|
||||||
|
cosine = 2.0;
|
||||||
v = 0.0;
|
v = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +279,9 @@ inline boolean Move::LookAheadRingEmpty()
|
||||||
|
|
||||||
inline boolean Move::LookAheadRingFull()
|
inline boolean Move::LookAheadRingFull()
|
||||||
{
|
{
|
||||||
return lookAheadRingAddPointer->Next()->Next() == lookAheadRingGetPointer;
|
if(!(lookAheadRingAddPointer->Processed() & released))
|
||||||
|
return true;
|
||||||
|
return lookAheadRingAddPointer->Next()->Next() == lookAheadRingGetPointer; // probably not needed; just return the boolean in the if above
|
||||||
}
|
}
|
||||||
|
|
||||||
inline boolean Move::GetDDARingLock()
|
inline boolean Move::GetDDARingLock()
|
||||||
|
@ -311,16 +314,14 @@ inline void Move::ResumeMoving()
|
||||||
addNoMoreMoves = false;
|
addNoMoreMoves = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Move::HitLowStop(int8_t drive)
|
inline void Move::HitLowStop(int8_t drive, LookAhead* la)
|
||||||
{
|
{
|
||||||
currentPosition[drive] = 0.0;
|
la->SetDriveZeroEndSpeed(0.0, drive);
|
||||||
lookAheadRingGetPointer->Previous()->SetDriveZeroEndSpeed(0.0, drive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Move::HitHighStop(int8_t drive)
|
inline void Move::HitHighStop(int8_t drive, LookAhead* la)
|
||||||
{
|
{
|
||||||
currentPosition[drive] = platform->AxisLength(drive);
|
la->SetDriveZeroEndSpeed(platform->AxisLength(drive), drive);
|
||||||
lookAheadRingGetPointer->Previous()->SetDriveZeroEndSpeed(currentPosition[drive], drive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
81
Move.ino
81
Move.ino
|
@ -45,7 +45,7 @@ Move::Move(Platform* p, GCodes* g)
|
||||||
lookAheadRingGetPointer = new LookAhead(this, platform, lookAheadRingGetPointer);
|
lookAheadRingGetPointer = new LookAhead(this, platform, lookAheadRingGetPointer);
|
||||||
lookAheadRingAddPointer->next = lookAheadRingGetPointer;
|
lookAheadRingAddPointer->next = lookAheadRingGetPointer;
|
||||||
|
|
||||||
// Set the backwards pointers and flag them all as free
|
// Set the backwards pointers
|
||||||
|
|
||||||
lookAheadRingGetPointer = lookAheadRingAddPointer;
|
lookAheadRingGetPointer = lookAheadRingAddPointer;
|
||||||
for(i = 0; i <= LOOK_AHEAD_RING_LENGTH; i++)
|
for(i = 0; i <= LOOK_AHEAD_RING_LENGTH; i++)
|
||||||
|
@ -66,12 +66,6 @@ void Move::Init()
|
||||||
for(i = 0; i < DRIVES; i++)
|
for(i = 0; i < DRIVES; i++)
|
||||||
platform->SetDirection(i, FORWARDS);
|
platform->SetDirection(i, FORWARDS);
|
||||||
|
|
||||||
// Set the current position to the origin
|
|
||||||
|
|
||||||
for(i = 0; i <= AXES; i++)
|
|
||||||
currentPosition[i] = 0.0;
|
|
||||||
currentFeedrate = START_FEED_RATE;
|
|
||||||
|
|
||||||
// Empty the rings
|
// Empty the rings
|
||||||
|
|
||||||
ddaRingGetPointer = ddaRingAddPointer;
|
ddaRingGetPointer = ddaRingAddPointer;
|
||||||
|
@ -91,9 +85,12 @@ void Move::Init()
|
||||||
// Put the origin on the lookahead ring with zero velocity in the previous
|
// Put the origin on the lookahead ring with zero velocity in the previous
|
||||||
// position to the first one that will be used.
|
// position to the first one that will be used.
|
||||||
|
|
||||||
|
lastMove = lookAheadRingAddPointer->Previous();
|
||||||
|
|
||||||
for(i = 0; i < DRIVES; i++)
|
for(i = 0; i < DRIVES; i++)
|
||||||
lookAheadRingGetPointer->Previous()->SetDriveZeroEndSpeed(0.0, i);
|
lastMove->SetDriveZeroEndSpeed(0.0, i);
|
||||||
lookAheadRingGetPointer->Previous()->SetDriveZeroEndSpeed(currentFeedrate, DRIVES);
|
|
||||||
|
lastMove->SetDriveZeroEndSpeed(START_FEED_RATE, DRIVES);
|
||||||
|
|
||||||
checkEndStopsOnNextMove = false;
|
checkEndStopsOnNextMove = false;
|
||||||
|
|
||||||
|
@ -138,8 +135,8 @@ void Move::Init()
|
||||||
stepDistances[0] = 1.0/platform->DriveStepsPerUnit(AXES);
|
stepDistances[0] = 1.0/platform->DriveStepsPerUnit(AXES);
|
||||||
extruderStepDistances[0] = stepDistances[0];
|
extruderStepDistances[0] = stepDistances[0];
|
||||||
|
|
||||||
|
currentFeedrate = -1.0;
|
||||||
|
|
||||||
currentFeedrate = START_FEED_RATE;
|
|
||||||
lastTime = platform->Time();
|
lastTime = platform->Time();
|
||||||
active = true;
|
active = true;
|
||||||
}
|
}
|
||||||
|
@ -171,19 +168,20 @@ void Move::Spin()
|
||||||
|
|
||||||
if(gCodes->ReadMove(nextMove, checkEndStopsOnNextMove))
|
if(gCodes->ReadMove(nextMove, checkEndStopsOnNextMove))
|
||||||
{
|
{
|
||||||
if(GetMovementType(currentPosition, nextMove) == noMove)
|
currentFeedrate = nextMove[DRIVES]; // Might be G1 with just an F field
|
||||||
{
|
if(GetMovementType(lastMove->EndPoint(), nextMove) == noMove) // Throw it away if there's no real movement.
|
||||||
currentFeedrate = nextMove[DRIVES]; // Might be G1 with just an F field
|
|
||||||
return;
|
return;
|
||||||
}
|
currentFeedrate = -1.0; // Real move - record its feedrate with it, not here.
|
||||||
if(!LookAheadRingAdd(nextMove, 0.0, checkEndStopsOnNextMove))
|
if(!LookAheadRingAdd(nextMove, 0.0, checkEndStopsOnNextMove))
|
||||||
platform->Message(HOST_MESSAGE, "Can't add to non-full look ahead ring!\n"); // Should never happen...
|
platform->Message(HOST_MESSAGE, "Can't add to non-full look ahead ring!\n"); // Should never happen...
|
||||||
for(int8_t i = 0; i < AXES; i++)
|
|
||||||
currentPosition[i] = nextMove[i];
|
|
||||||
currentFeedrate = nextMove[DRIVES];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This returns false if it is not possible
|
||||||
|
// to use the result as the basis for the
|
||||||
|
// next move because the look ahead ring
|
||||||
|
// is full. True otherwise.
|
||||||
|
|
||||||
boolean Move::GetCurrentState(float m[])
|
boolean Move::GetCurrentState(float m[])
|
||||||
{
|
{
|
||||||
if(LookAheadRingFull())
|
if(LookAheadRingFull())
|
||||||
|
@ -192,11 +190,15 @@ boolean Move::GetCurrentState(float m[])
|
||||||
for(int8_t i = 0; i < DRIVES; i++)
|
for(int8_t i = 0; i < DRIVES; i++)
|
||||||
{
|
{
|
||||||
if(i < AXES)
|
if(i < AXES)
|
||||||
m[i] = currentPosition[i];
|
m[i] = lastMove->EndPoint()[i];
|
||||||
else
|
else
|
||||||
m[i] = 0.0;
|
m[i] = 0.0;
|
||||||
}
|
}
|
||||||
m[DRIVES] = currentFeedrate;
|
if(currentFeedrate >= 0.0)
|
||||||
|
m[DRIVES] = currentFeedrate;
|
||||||
|
else
|
||||||
|
m[DRIVES] = lastMove->EndPoint()[DRIVES];
|
||||||
|
currentFeedrate = -1.0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,9 +235,9 @@ boolean Move::DDARingAdd(LookAhead* lookAhead)
|
||||||
ReleaseDDARingLock();
|
ReleaseDDARingLock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(ddaRingAddPointer->Active())
|
if(ddaRingAddPointer->Active()) // Should never happen...
|
||||||
{
|
{
|
||||||
platform->Message(HOST_MESSAGE, "Attempt to alter an active ring buffer entry!\n"); // Should never happen...
|
platform->Message(HOST_MESSAGE, "Attempt to alter an active ring buffer entry!\n");
|
||||||
ReleaseDDARingLock();
|
ReleaseDDARingLock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -283,7 +285,7 @@ void Move::DoLookAhead()
|
||||||
|
|
||||||
float u, v;
|
float u, v;
|
||||||
|
|
||||||
if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > LOOK_AHEAD)
|
/* if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > LOOK_AHEAD)
|
||||||
{
|
{
|
||||||
n1 = lookAheadRingGetPointer;
|
n1 = lookAheadRingGetPointer;
|
||||||
n0 = n1->Previous();
|
n0 = n1->Previous();
|
||||||
|
@ -330,7 +332,7 @@ void Move::DoLookAhead()
|
||||||
}while(n0 != lookAheadRingGetPointer);
|
}while(n0 != lookAheadRingGetPointer);
|
||||||
n0->SetProcessed(complete);
|
n0->SetProcessed(complete);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > 1)
|
if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > 1)
|
||||||
{
|
{
|
||||||
n1 = lookAheadRingGetPointer;
|
n1 = lookAheadRingGetPointer;
|
||||||
|
@ -340,8 +342,8 @@ void Move::DoLookAhead()
|
||||||
{
|
{
|
||||||
if(n1->Processed() == unprocessed)
|
if(n1->Processed() == unprocessed)
|
||||||
{
|
{
|
||||||
float c = n1->Cosine();
|
float c = fmin(n1->EndPoint()[DRIVES], n2->EndPoint()[DRIVES]);
|
||||||
c = n1->EndPoint()[DRIVES]*c;
|
c = c*n1->Cosine();
|
||||||
if(c <= 0)
|
if(c <= 0)
|
||||||
{
|
{
|
||||||
int8_t mt = GetMovementType(n0->EndPoint(), n1->EndPoint());
|
int8_t mt = GetMovementType(n0->EndPoint(), n1->EndPoint());
|
||||||
|
@ -353,7 +355,8 @@ void Move::DoLookAhead()
|
||||||
c = platform->InstantDv(AXES); // value for first extruder - slight hack
|
c = platform->InstantDv(AXES); // value for first extruder - slight hack
|
||||||
}
|
}
|
||||||
n1->SetV(c);
|
n1->SetV(c);
|
||||||
n1->SetProcessed(vCosineSet);
|
//n1->SetProcessed(vCosineSet);
|
||||||
|
n1->SetProcessed(complete);
|
||||||
}
|
}
|
||||||
n0 = n1;
|
n0 = n1;
|
||||||
n1 = n2;
|
n1 = n2;
|
||||||
|
@ -403,7 +406,10 @@ boolean Move::LookAheadRingAdd(float ep[], float vv, boolean ce)
|
||||||
{
|
{
|
||||||
if(LookAheadRingFull())
|
if(LookAheadRingFull())
|
||||||
return false;
|
return false;
|
||||||
|
if(!(lookAheadRingAddPointer->Processed() & released))
|
||||||
|
platform->Message(HOST_MESSAGE, "Attempt to alter a non-released lookahead ring entry!\n"); // Should never happen...
|
||||||
lookAheadRingAddPointer->Init(ep, vv, ce);
|
lookAheadRingAddPointer->Init(ep, vv, ce);
|
||||||
|
lastMove = lookAheadRingAddPointer;
|
||||||
lookAheadRingAddPointer = lookAheadRingAddPointer->Next();
|
lookAheadRingAddPointer = lookAheadRingAddPointer->Next();
|
||||||
lookAheadRingCount++;
|
lookAheadRingCount++;
|
||||||
return true;
|
return true;
|
||||||
|
@ -511,14 +517,15 @@ MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
|
||||||
{
|
{
|
||||||
int8_t drive;
|
int8_t drive;
|
||||||
active = false;
|
active = false;
|
||||||
|
myLookAheadEntry = lookAhead;
|
||||||
MovementProfile result = moving;
|
MovementProfile result = moving;
|
||||||
totalSteps = -1;
|
totalSteps = -1;
|
||||||
distance = 0.0; // X+Y+Z
|
distance = 0.0; // X+Y+Z
|
||||||
float eDistance = 0.0;
|
float eDistance = 0.0;
|
||||||
float d;
|
float d;
|
||||||
float* targetPosition = lookAhead->EndPoint();
|
float* targetPosition = myLookAheadEntry->EndPoint();
|
||||||
v = lookAhead->V();
|
v = lookAhead->V();
|
||||||
float* positionNow = lookAhead->Previous()->EndPoint();
|
float* positionNow = myLookAheadEntry->Previous()->EndPoint();
|
||||||
u = lookAhead->Previous()->V();
|
u = lookAhead->Previous()->V();
|
||||||
checkEndStops = lookAhead->CheckEndStops();
|
checkEndStops = lookAhead->CheckEndStops();
|
||||||
|
|
||||||
|
@ -554,13 +561,12 @@ MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
|
||||||
if(totalSteps <= 0)
|
if(totalSteps <= 0)
|
||||||
{
|
{
|
||||||
platform->Message(HOST_MESSAGE, "DDA.Init(): Null movement!\n");
|
platform->Message(HOST_MESSAGE, "DDA.Init(): Null movement!\n");
|
||||||
|
myLookAheadEntry->Release();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the DDA
|
// Set up the DDA
|
||||||
|
|
||||||
result = moving;
|
|
||||||
|
|
||||||
counter[0] = -totalSteps/2;
|
counter[0] = -totalSteps/2;
|
||||||
for(drive = 1; drive < DRIVES; drive++)
|
for(drive = 1; drive < DRIVES; drive++)
|
||||||
counter[drive] = counter[0];
|
counter[drive] = counter[0];
|
||||||
|
@ -685,8 +691,6 @@ MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
|
||||||
|
|
||||||
timeStep = timeStep/velocity;
|
timeStep = timeStep/velocity;
|
||||||
|
|
||||||
lookAhead->Release();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,12 +733,12 @@ void DDA::Step(boolean noTest)
|
||||||
EndStopHit esh = platform->Stopped(drive);
|
EndStopHit esh = platform->Stopped(drive);
|
||||||
if(esh == lowHit)
|
if(esh == lowHit)
|
||||||
{
|
{
|
||||||
move->HitLowStop(drive);
|
move->HitLowStop(drive, myLookAheadEntry);
|
||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
if(esh == highHit)
|
if(esh == highHit)
|
||||||
{
|
{
|
||||||
move->HitHighStop(drive);
|
move->HitHighStop(drive, myLookAheadEntry);
|
||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -758,15 +762,18 @@ void DDA::Step(boolean noTest)
|
||||||
if(stepCount >= startDStep)
|
if(stepCount >= startDStep)
|
||||||
velocity -= acceleration*timeStep;
|
velocity -= acceleration*timeStep;
|
||||||
|
|
||||||
if(noTest)
|
|
||||||
platform->SetInterrupt((long)(1.0e6*timeStep));
|
|
||||||
|
|
||||||
stepCount++;
|
stepCount++;
|
||||||
active = stepCount < totalSteps;
|
active = stepCount < totalSteps;
|
||||||
|
|
||||||
|
if(noTest)
|
||||||
|
platform->SetInterrupt((long)(1.0e6*timeStep));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!active && noTest)
|
if(!active && noTest)
|
||||||
|
{
|
||||||
|
myLookAheadEntry->Release();
|
||||||
platform->SetInterrupt(STANDBY_INTERRUPT_RATE);
|
platform->SetInterrupt(STANDBY_INTERRUPT_RATE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//***************************************************************************************************
|
//***************************************************************************************************
|
||||||
|
|
|
@ -77,8 +77,8 @@ Licence: GPL
|
||||||
#define HIGH_STOP_PINS {-1, -1, -1, -1}
|
#define HIGH_STOP_PINS {-1, -1, -1, -1}
|
||||||
#define ENDSTOP_HIT 1 // when a stop == this it is hit
|
#define ENDSTOP_HIT 1 // when a stop == this it is hit
|
||||||
#define MAX_FEEDRATES {300, 300, 3, 45} // mm/sec
|
#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 ACCELERATIONS {80, 80, 3, 25}
|
||||||
#define DRIVE_STEPS_PER_UNIT {91.4286, 91.4286, 4000, 929}
|
#define DRIVE_STEPS_PER_UNIT {91.4286, 91.4286, 4000, 929}
|
||||||
#define INSTANT_DVS {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
|
#define GCODE_LETTERS { 'X', 'Y', 'Z', 'E', 'F' } // The drives and feedrate in a GCode
|
||||||
|
|
123
README
123
README
|
@ -1,28 +1,125 @@
|
||||||
This firmware is intended to be a fully object-oriented highly modular control p
|
RepRapFirmware - Main Program
|
||||||
rogram for RepRap self-replicating 3D printers.
|
|
||||||
|
This firmware is intended to be a fully object-oriented highly modular control program for
|
||||||
|
RepRap self-replicating 3D printers.
|
||||||
|
|
||||||
It owes a lot to Marlin and to the original RepRap FiveD_GCode.
|
It owes a lot to Marlin and to the original RepRap FiveD_GCode.
|
||||||
|
|
||||||
|
|
||||||
General design principles:
|
General design principles:
|
||||||
|
|
||||||
* Control by RepRap G Codes. These are taken to be machine independent,
|
* Control by RepRap G Codes. These are taken to be machine independent, though some may be unsupported.
|
||||||
though some may be unsupported.
|
|
||||||
* Full use of C++ OO techniques,
|
* Full use of C++ OO techniques,
|
||||||
* Make classes hide their data,
|
* Make classes hide their data,
|
||||||
* Make everything as stateless as possible,
|
* Make everything as stateless as possible,
|
||||||
* No use of conditional compilation except for #include guards - if you
|
* No use of conditional compilation except for #include guards - if you need that, you should be
|
||||||
need that, you should be forking the repository to make a new
|
forking the repository to make a new branch - let the repository take the strain,
|
||||||
branch - let the repository take the strain,
|
* Concentration of all machine-dependent defintions and code in Platform.h and Platform.cpp,
|
||||||
* Concentration of all machine-dependent defintions and code in Platform.h
|
|
||||||
and Platform.cpp,
|
|
||||||
* No specials for (X,Y) or (Z) - all movement is 3-dimensional,
|
* No specials for (X,Y) or (Z) - all movement is 3-dimensional,
|
||||||
* Try to be efficient in memory use, but this is not critical,
|
* Try to be efficient in memory use, but this is not critical,
|
||||||
* Labour hard to be efficient in time use, and this is critical,
|
* Labour hard to be efficient in time use, and this is critical,
|
||||||
* Don't abhor floats - they work fast enough if you're clever,
|
* Don't abhor floats - they work fast enough if you're clever,
|
||||||
* Don't avoid arrays and structs/classes,
|
* Don't avoid arrays and structs/classes,
|
||||||
* Don't avoid pointers,
|
* Don't avoid pointers,
|
||||||
* Use operator and function overloading where appropriate, particulary for
|
* Use operator and function overloading where appropriate, particularly for vector algebra.
|
||||||
vector algebra.
|
|
||||||
|
|
||||||
|
Naming conventions:
|
||||||
|
|
||||||
|
* #defines are all capitals with optional underscores between words
|
||||||
|
* No underscores in other names - MakeReadableWithCapitalisation
|
||||||
|
* Class names and functions start with a CapitalLetter
|
||||||
|
* Variables start with a lowerCaseLetter
|
||||||
|
* Use veryLongDescriptiveNames
|
||||||
|
|
||||||
|
|
||||||
|
Structure:
|
||||||
|
|
||||||
|
There are six main classes:
|
||||||
|
|
||||||
|
* RepRap
|
||||||
|
* GCodes
|
||||||
|
* Heat
|
||||||
|
* Move
|
||||||
|
* Platform, and
|
||||||
|
* Webserver
|
||||||
|
|
||||||
|
RepRap:
|
||||||
|
|
||||||
|
This is just a container class for the single instances of all the others, and otherwise does very little.
|
||||||
|
|
||||||
|
GCodes:
|
||||||
|
|
||||||
|
This class is fed GCodes, either from the web interface or from GCode files, interprests them, and requests
|
||||||
|
actions from the RepRap machine via the other classes.
|
||||||
|
|
||||||
|
Heat:
|
||||||
|
|
||||||
|
This class imlements all heating and temperature control in the RepRap machine.
|
||||||
|
|
||||||
|
Move:
|
||||||
|
|
||||||
|
This class controls all movement of the RepRap machine, both along its axes, and in its extruder drives.
|
||||||
|
|
||||||
|
Platform:
|
||||||
|
|
||||||
|
This is the only class that knows anything about the physical setup of the RepRap machine and its
|
||||||
|
controlling electronics. It implements the interface between all the other classes and the RepRap machine.
|
||||||
|
All the other classes are completely machine-independent (though they may declare arrays dimensioned
|
||||||
|
to values #defined in Platform.h).
|
||||||
|
|
||||||
|
Webserver:
|
||||||
|
|
||||||
|
This class talks to the network (via Platform) and implements a simple webserver to give an interactive
|
||||||
|
interface to the RepRap machine. It uses the Knockout and Jquery Javascript libraries to achieve this.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
When the software is running there is one single instance of each main class, and all the memory allocation is
|
||||||
|
done on initialisation. new/malloc should not be used in the general running code, and delete is never
|
||||||
|
used. Each class has an Init() function that resets it to its boot-up state; the constructors merely handle
|
||||||
|
that memory allocation on startup. Calling RepRap.Init() calls all the other Init()s in the right sequence.
|
||||||
|
|
||||||
|
There are other ancilliary classes that are declared in the .h files for the master classes that use them. For
|
||||||
|
example, Move has a DDA class that implements a Bresenham/digital differential analyser.
|
||||||
|
|
||||||
|
|
||||||
|
Timing:
|
||||||
|
|
||||||
|
There is a single interrupt chain entered via Platform.Interrupt(). This controls movement step timing, and
|
||||||
|
this chain of code should be the only place that volatile declarations and structure/variable-locking are
|
||||||
|
required. All the rest of the code is called sequentially and repeatedly as follows:
|
||||||
|
|
||||||
|
All the main classes have a Spin() function. These are called in a loop by the RepRap.Spin() function and implement
|
||||||
|
simple timesharing. No class does, or ever should, wait inside one of its functions for anything to happen or call
|
||||||
|
any sort of delay() function. The general rule is:
|
||||||
|
|
||||||
|
Can I do a thing?
|
||||||
|
Yes - do it
|
||||||
|
No - set a flag/timer to remind me to do it next-time-I'm-called/at-a-future-time and return.
|
||||||
|
|
||||||
|
The restriction this strategy places on almost all the code in the firmware (that it must execute quickly and
|
||||||
|
never cause waits or delays) is balanced by the fact that none of that code needs to worry about synchronicity,
|
||||||
|
locking, or other areas of code accessing items upon which it is working. As mentioned, only the interrupt
|
||||||
|
chain needs to concern itself with such problems. Unlike movement, heating (including PID controllers) does
|
||||||
|
not need the fast precision of timing that interrupts alone can offer. Indeed, most heating code only needs
|
||||||
|
to execute a couple of times a second.
|
||||||
|
|
||||||
|
Most data is transferred bytewise, with classes typically containg code like this:
|
||||||
|
|
||||||
|
Is a byte available for me?
|
||||||
|
Yes
|
||||||
|
read it and add it to my buffer
|
||||||
|
Is my buffer complete?
|
||||||
|
Yes
|
||||||
|
Act on the contents of my buffer
|
||||||
|
No
|
||||||
|
Return
|
||||||
|
No
|
||||||
|
Return
|
||||||
|
|
||||||
|
Note that it is simple to raise the "priority" of any class's activities relative to the others by calling its
|
||||||
|
Spin() function more than once from RepRap.Spin().
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -49,7 +146,7 @@ The password when the web browser asks for it is "reprap" with no quotes.
|
||||||
|
|
||||||
The password is intended to stop fidgety friends or colleagues from playing
|
The password is intended to stop fidgety friends or colleagues from playing
|
||||||
with your RepRap. It is not intended to stop international cyberterrorists
|
with your RepRap. It is not intended to stop international cyberterrorists
|
||||||
working in a hollowed-out volcano from controlling your RepRap from the next
|
hiding in a hollowed-out volcano from controlling your RepRap from the next
|
||||||
continent. For example, it is transmitted unencrypted...
|
continent. For example, it is transmitted unencrypted...
|
||||||
|
|
||||||
If you open the Arduino serial monitor (115200 baud) you should see a
|
If you open the Arduino serial monitor (115200 baud) you should see a
|
||||||
|
@ -63,7 +160,7 @@ Actually acting upon them will be added shortly :-)
|
||||||
Version 0.2 pre-alpha
|
Version 0.2 pre-alpha
|
||||||
|
|
||||||
Started: 18 November 2012
|
Started: 18 November 2012
|
||||||
This date: 1 March 2013
|
This date: 12 June 2013
|
||||||
|
|
||||||
Adrian Bowyer
|
Adrian Bowyer
|
||||||
RepRap Professional Ltd
|
RepRap Professional Ltd
|
||||||
|
|
123
README~
123
README~
|
@ -1,28 +1,125 @@
|
||||||
This firmware is intended to be a fully object-oriented highly modular control p
|
RepRapFirmware - Main Program
|
||||||
rogram for RepRap self-replicating 3D printers.
|
|
||||||
|
This firmware is intended to be a fully object-oriented highly modular control program for
|
||||||
|
RepRap self-replicating 3D printers.
|
||||||
|
|
||||||
It owes a lot to Marlin and to the original RepRap FiveD_GCode.
|
It owes a lot to Marlin and to the original RepRap FiveD_GCode.
|
||||||
|
|
||||||
|
|
||||||
General design principles:
|
General design principles:
|
||||||
|
|
||||||
* Control by RepRap G Codes. These are taken to be machine independent,
|
* Control by RepRap G Codes. These are taken to be machine independent, though some may be unsupported.
|
||||||
though some may be unsupported.
|
|
||||||
* Full use of C++ OO techniques,
|
* Full use of C++ OO techniques,
|
||||||
* Make classes hide their data,
|
* Make classes hide their data,
|
||||||
* Make everything as stateless as possible,
|
* Make everything as stateless as possible,
|
||||||
* No use of conditional compilation except for #include guards - if you
|
* No use of conditional compilation except for #include guards - if you need that, you should be
|
||||||
need that, you should be forking the repository to make a new
|
forking the repository to make a new branch - let the repository take the strain,
|
||||||
branch - let the repository take the strain,
|
* Concentration of all machine-dependent defintions and code in Platform.h and Platform.cpp,
|
||||||
* Concentration of all machine-dependent defintions and code in Platform.h
|
|
||||||
and Platform.cpp,
|
|
||||||
* No specials for (X,Y) or (Z) - all movement is 3-dimensional,
|
* No specials for (X,Y) or (Z) - all movement is 3-dimensional,
|
||||||
* Try to be efficient in memory use, but this is not critical,
|
* Try to be efficient in memory use, but this is not critical,
|
||||||
* Labour hard to be efficient in time use, and this is critical,
|
* Labour hard to be efficient in time use, and this is critical,
|
||||||
* Don't abhor floats - they work fast enough if you're clever,
|
* Don't abhor floats - they work fast enough if you're clever,
|
||||||
* Don't avoid arrays and structs/classes,
|
* Don't avoid arrays and structs/classes,
|
||||||
* Don't avoid pointers,
|
* Don't avoid pointers,
|
||||||
* Use operator and function overloading where appropriate, particulary for
|
* Use operator and function overloading where appropriate, particularly for vector algebra.
|
||||||
vector algebra.
|
|
||||||
|
|
||||||
|
Naming conventions:
|
||||||
|
|
||||||
|
* #defines are all capitals with optional underscores between words
|
||||||
|
* No underscores in other names - MakeReadableWithCapitalisation
|
||||||
|
* Class names and functions start with a CapitalLetter
|
||||||
|
* Variables start with a lowerCaseLetter
|
||||||
|
* Use veryLongDescriptiveNames
|
||||||
|
|
||||||
|
|
||||||
|
Structure:
|
||||||
|
|
||||||
|
There are six main classes:
|
||||||
|
|
||||||
|
* RepRap
|
||||||
|
* GCodes
|
||||||
|
* Heat
|
||||||
|
* Move
|
||||||
|
* Platform, and
|
||||||
|
* Webserver
|
||||||
|
|
||||||
|
RepRap:
|
||||||
|
|
||||||
|
This is just a container class for the single instances of all the others, and otherwise does very little.
|
||||||
|
|
||||||
|
GCodes:
|
||||||
|
|
||||||
|
This class is fed GCodes, either from the web interface or from GCode files, interprests them, and requests
|
||||||
|
actions from the RepRap machine via the other classes.
|
||||||
|
|
||||||
|
Heat:
|
||||||
|
|
||||||
|
This class imlements all heating and temperature control in the RepRap machine.
|
||||||
|
|
||||||
|
Move:
|
||||||
|
|
||||||
|
This class controls all movement of the RepRap machine, both along its axes, and in its extruder drives.
|
||||||
|
|
||||||
|
Platform:
|
||||||
|
|
||||||
|
This is the only class that knows anything about the physical setup of the RepRap machine and its
|
||||||
|
controlling electronics. It implements the interface between all the other classes and the RepRap machine.
|
||||||
|
All the other classes are completely machine-independent (though they may declare arrays dimensioned
|
||||||
|
to values #defined in Platform.h).
|
||||||
|
|
||||||
|
Webserver:
|
||||||
|
|
||||||
|
This class talks to the network (via Platform) and implements a simple webserver to give an interactive
|
||||||
|
interface to the RepRap machine. It uses the Knockout and Jquery Javascript libraries to achieve this.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
When the software is running there is one single instance of each main class, and all the memory allocation is
|
||||||
|
done on initialisation. new/malloc should not be used in the general running code, and delete is never
|
||||||
|
used. Each class has an Init() function that resets it to its boot-up state; the constructors merely handle
|
||||||
|
that memory allocation on startup. Calling RepRap.Init() calls all the other Init()s in the right sequence.
|
||||||
|
|
||||||
|
There are other ancilliary classes that are declared in the .h files for the master classes that use them. For
|
||||||
|
example, Move has a DDA class that implements a Bresenham/digital differential analyser.
|
||||||
|
|
||||||
|
|
||||||
|
Timing:
|
||||||
|
|
||||||
|
There is a single interrupt chain entered via Platform.Interrupt(). This controls movement step timing, and
|
||||||
|
this chain of code should be the only place that volatile declarations and structure/variable-locking are
|
||||||
|
required. All the rest of the code is called sequentially and repeatedly as follows:
|
||||||
|
|
||||||
|
All the main classes have a Spin() function. These are called in a loop by the RepRap.Spin() function and implement
|
||||||
|
simple timesharing. No class does, or ever should, wait inside one of its functions for anything to happen or call
|
||||||
|
any sort of delay() function. The general rule is:
|
||||||
|
|
||||||
|
Can I do a thing?
|
||||||
|
Yes - do it
|
||||||
|
No - set a flag/timer to remind me to do it next-time-I'm-called/at-a-future-time and return.
|
||||||
|
|
||||||
|
The restriction this strategy places on almost all the code in the firmware (that it must execute quickly and
|
||||||
|
never cause waits or delays) is balanced by the fact that none of that code needs to worry about synchronicity,
|
||||||
|
locking, or other areas of code accessing items upon which it is working. As mentioned, only the interrupt
|
||||||
|
chain needs to concern itself with such problems. Unlike movement, heating (including PID controllers) does
|
||||||
|
not need the fast precision of timing that interrupts alone can offer. Indeed, most heating code only needs
|
||||||
|
to execute a couple of times a second.
|
||||||
|
|
||||||
|
Most data is transferred bytewise, with classes typically containg code like this:
|
||||||
|
|
||||||
|
Is a byte available for me?
|
||||||
|
Yes
|
||||||
|
read it and add it to my buffer
|
||||||
|
Is my buffer complete?
|
||||||
|
Yes
|
||||||
|
Act on the contents of my buffer
|
||||||
|
No
|
||||||
|
Return
|
||||||
|
No
|
||||||
|
Return
|
||||||
|
|
||||||
|
Note that it is simple to raise the "priority" of any class's activities relative to the others by calling its
|
||||||
|
Spin() function more than once from RepRap.Spin().
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -31,7 +128,7 @@ the RepRapPro Ltd Arduino DUE to Sanguinololu Adaptor.
|
||||||
|
|
||||||
(See https://github.com/reprappro/ARMadaptor)
|
(See https://github.com/reprappro/ARMadaptor)
|
||||||
|
|
||||||
Test compiling is with Arduino 1.5.2.
|
Test compiling was with Arduino 1.5.2.
|
||||||
|
|
||||||
Upload it to your Due, put the ether shield on it, plug in a
|
Upload it to your Due, put the ether shield on it, plug in a
|
||||||
network cable, and copy the files in the SD-image folder onto the SD.
|
network cable, and copy the files in the SD-image folder onto the SD.
|
||||||
|
@ -63,7 +160,7 @@ Actually acting upon them will be added shortly :-)
|
||||||
Version 0.2 pre-alpha
|
Version 0.2 pre-alpha
|
||||||
|
|
||||||
Started: 18 November 2012
|
Started: 18 November 2012
|
||||||
This date: 1 March 2013
|
This date: 12 June 2013
|
||||||
|
|
||||||
Adrian Bowyer
|
Adrian Bowyer
|
||||||
RepRap Professional Ltd
|
RepRap Professional Ltd
|
||||||
|
|
|
@ -77,7 +77,7 @@ interface to the RepRap machine. It uses the Knockout and Jquery Javascript lib
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
When the software is running there is one single instance of each class, and all the memory allocation is
|
When the software is running there is one single instance of each main class, and all the memory allocation is
|
||||||
done on initialisation. new/malloc should not be used in the general running code, and delete is never
|
done on initialisation. new/malloc should not be used in the general running code, and delete is never
|
||||||
used. Each class has an Init() function that resets it to its boot-up state; the constructors merely handle
|
used. Each class has an Init() function that resets it to its boot-up state; the constructors merely handle
|
||||||
that memory allocation on startup. Calling RepRap.Init() calls all the other Init()s in the right sequence.
|
that memory allocation on startup. Calling RepRap.Init() calls all the other Init()s in the right sequence.
|
||||||
|
@ -85,6 +85,13 @@ that memory allocation on startup. Calling RepRap.Init() calls all the other In
|
||||||
There are other ancilliary classes that are declared in the .h files for the master classes that use them. For
|
There are other ancilliary classes that are declared in the .h files for the master classes that use them. For
|
||||||
example, Move has a DDA class that implements a Bresenham/digital differential analyser.
|
example, Move has a DDA class that implements a Bresenham/digital differential analyser.
|
||||||
|
|
||||||
|
|
||||||
|
Timing:
|
||||||
|
|
||||||
|
There is a single interrupt chain entered via Platform.Interrupt(). This controls movement step timing, and
|
||||||
|
this chain of code should be the only place that volatile declarations and structure/variable-locking are
|
||||||
|
required. All the rest of the code is called sequentially and repeatedly as follows:
|
||||||
|
|
||||||
All the main classes have a Spin() function. These are called in a loop by the RepRap.Spin() function and implement
|
All the main classes have a Spin() function. These are called in a loop by the RepRap.Spin() function and implement
|
||||||
simple timesharing. No class does, or ever should, wait inside one of its functions for anything to happen or call
|
simple timesharing. No class does, or ever should, wait inside one of its functions for anything to happen or call
|
||||||
any sort of delay() function. The general rule is:
|
any sort of delay() function. The general rule is:
|
||||||
|
@ -93,6 +100,26 @@ any sort of delay() function. The general rule is:
|
||||||
Yes - do it
|
Yes - do it
|
||||||
No - set a flag/timer to remind me to do it next-time-I'm-called/at-a-future-time and return.
|
No - set a flag/timer to remind me to do it next-time-I'm-called/at-a-future-time and return.
|
||||||
|
|
||||||
|
The restriction this strategy places on almost all the code in the firmware (that it must execute quickly and
|
||||||
|
never cause waits or delays) is balanced by the fact that none of that code needs to worry about synchronicity,
|
||||||
|
locking, or other areas of code accessing items upon which it is working. As mentioned, only the interrupt
|
||||||
|
chain needs to concern itself with such problems. Unlike movement, heating (including PID controllers) does
|
||||||
|
not need the fast precision of timing that interrupts alone can offer. Indeed, most heating code only needs
|
||||||
|
to execute a couple of times a second.
|
||||||
|
|
||||||
|
Most data is transferred bytewise, with classes typically containg code like this:
|
||||||
|
|
||||||
|
Is a byte available for me?
|
||||||
|
Yes
|
||||||
|
read it and add it to my buffer
|
||||||
|
Is my buffer complete?
|
||||||
|
Yes
|
||||||
|
Act on the contents of my buffer
|
||||||
|
No
|
||||||
|
Return
|
||||||
|
No
|
||||||
|
Return
|
||||||
|
|
||||||
Note that it is simple to raise the "priority" of any class's activities relative to the others by calling its
|
Note that it is simple to raise the "priority" of any class's activities relative to the others by calling its
|
||||||
Spin() function more than once from RepRap.Spin().
|
Spin() function more than once from RepRap.Spin().
|
||||||
|
|
||||||
|
|
22
SD-image/gcodes/ktst.g
Normal file
22
SD-image/gcodes/ktst.g
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
G1 F1800.000 E-1.00000
|
||||||
|
G1 Z0.120 F3600.000
|
||||||
|
G1 X79.749 Y80.881
|
||||||
|
G1 F1800.000 E1.00000
|
||||||
|
G1 X79.979 Y80.671 F540.000 E0.00393
|
||||||
|
G1 X80.579 Y80.211 E0.00954
|
||||||
|
G1 X81.049 Y79.911 E0.00703
|
||||||
|
G1 X81.529 Y79.661 E0.00683
|
||||||
|
G1 X96.069 Y73.641 E0.19854
|
||||||
|
G1 X96.779 Y73.381 E0.00954
|
||||||
|
G1 X97.329 Y73.231 E0.00719
|
||||||
|
G1 X97.609 Y73.181 E0.00359
|
||||||
|
G1 X98.169 Y73.111 E0.00712
|
||||||
|
G1 X99.289 Y73.091 E0.01413
|
||||||
|
G1 X99.699 Y73.111 E0.00518
|
||||||
|
G1 X100.509 Y73.201 E0.01028
|
||||||
|
G1 X102.039 Y73.461 E0.01958
|
||||||
|
G1 X102.819 Y73.651 E0.01013
|
||||||
|
G1 X103.169 Y73.761 E0.00463
|
||||||
|
G1 X103.909 Y74.051 E0.01003
|
||||||
|
G1 X118.069 Y80.561 E0.19662
|
||||||
|
|
Reference in a new issue