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;
|
||||
float cosine;
|
||||
float v;
|
||||
int8_t processed;
|
||||
volatile int8_t processed;
|
||||
};
|
||||
|
||||
|
||||
|
@ -97,6 +97,7 @@ class DDA
|
|||
Move* move;
|
||||
Platform* platform;
|
||||
DDA* next;
|
||||
LookAhead* myLookAheadEntry;
|
||||
long counter[DRIVES];
|
||||
long delta[DRIVES];
|
||||
boolean directions[DRIVES];
|
||||
|
@ -131,8 +132,8 @@ class Move
|
|||
boolean AllMovesAreFinished();
|
||||
void ResumeMoving();
|
||||
void DoLookAhead();
|
||||
void HitLowStop(int8_t drive);
|
||||
void HitHighStop(int8_t drive);
|
||||
void HitLowStop(int8_t drive, LookAhead* la);
|
||||
void HitHighStop(int8_t drive, LookAhead* la);
|
||||
|
||||
friend class DDA;
|
||||
|
||||
|
@ -162,7 +163,7 @@ class Move
|
|||
|
||||
LookAhead* lookAheadRingAddPointer;
|
||||
LookAhead* lookAheadRingGetPointer;
|
||||
//LookAhead* larWaiting;
|
||||
LookAhead* lastMove;
|
||||
DDA* lookAheadDDA;
|
||||
int lookAheadRingCount;
|
||||
|
||||
|
@ -171,7 +172,6 @@ class Move
|
|||
boolean active;
|
||||
boolean checkEndStopsOnNextMove;
|
||||
float currentFeedrate;
|
||||
float currentPosition[AXES]; // Note - drives above AXES are always relative moves
|
||||
float nextMove[DRIVES + 1]; // Extra is for feedrate
|
||||
float stepDistances[(1<<AXES)]; // Index bits: lsb -> dx, dy, dz <- msb
|
||||
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)
|
||||
{
|
||||
if(ms == 0)
|
||||
processed = 0;
|
||||
if(ms == unprocessed)
|
||||
processed = unprocessed;
|
||||
else
|
||||
processed |= ms;
|
||||
}
|
||||
|
||||
inline void LookAhead::Release()
|
||||
{
|
||||
processed = released;
|
||||
SetProcessed(released);
|
||||
}
|
||||
|
||||
inline boolean LookAhead::CheckEndStops()
|
||||
|
@ -232,6 +232,7 @@ inline boolean LookAhead::CheckEndStops()
|
|||
inline void LookAhead::SetDriveZeroEndSpeed(float a, int8_t drive)
|
||||
{
|
||||
endPoint[drive] = a;
|
||||
cosine = 2.0;
|
||||
v = 0.0;
|
||||
}
|
||||
|
||||
|
@ -278,7 +279,9 @@ inline boolean Move::LookAheadRingEmpty()
|
|||
|
||||
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()
|
||||
|
@ -311,16 +314,14 @@ inline void Move::ResumeMoving()
|
|||
addNoMoreMoves = false;
|
||||
}
|
||||
|
||||
inline void Move::HitLowStop(int8_t drive)
|
||||
inline void Move::HitLowStop(int8_t drive, LookAhead* la)
|
||||
{
|
||||
currentPosition[drive] = 0.0;
|
||||
lookAheadRingGetPointer->Previous()->SetDriveZeroEndSpeed(0.0, drive);
|
||||
la->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);
|
||||
lookAheadRingGetPointer->Previous()->SetDriveZeroEndSpeed(currentPosition[drive], drive);
|
||||
la->SetDriveZeroEndSpeed(platform->AxisLength(drive), drive);
|
||||
}
|
||||
|
||||
|
||||
|
|
81
Move.ino
81
Move.ino
|
@ -45,7 +45,7 @@ Move::Move(Platform* p, GCodes* g)
|
|||
lookAheadRingGetPointer = new LookAhead(this, platform, lookAheadRingGetPointer);
|
||||
lookAheadRingAddPointer->next = lookAheadRingGetPointer;
|
||||
|
||||
// Set the backwards pointers and flag them all as free
|
||||
// Set the backwards pointers
|
||||
|
||||
lookAheadRingGetPointer = lookAheadRingAddPointer;
|
||||
for(i = 0; i <= LOOK_AHEAD_RING_LENGTH; i++)
|
||||
|
@ -66,12 +66,6 @@ void Move::Init()
|
|||
for(i = 0; i < DRIVES; i++)
|
||||
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
|
||||
|
||||
ddaRingGetPointer = ddaRingAddPointer;
|
||||
|
@ -91,9 +85,12 @@ void Move::Init()
|
|||
// Put the origin on the lookahead ring with zero velocity in the previous
|
||||
// position to the first one that will be used.
|
||||
|
||||
lastMove = lookAheadRingAddPointer->Previous();
|
||||
|
||||
for(i = 0; i < DRIVES; i++)
|
||||
lookAheadRingGetPointer->Previous()->SetDriveZeroEndSpeed(0.0, i);
|
||||
lookAheadRingGetPointer->Previous()->SetDriveZeroEndSpeed(currentFeedrate, DRIVES);
|
||||
lastMove->SetDriveZeroEndSpeed(0.0, i);
|
||||
|
||||
lastMove->SetDriveZeroEndSpeed(START_FEED_RATE, DRIVES);
|
||||
|
||||
checkEndStopsOnNextMove = false;
|
||||
|
||||
|
@ -138,8 +135,8 @@ void Move::Init()
|
|||
stepDistances[0] = 1.0/platform->DriveStepsPerUnit(AXES);
|
||||
extruderStepDistances[0] = stepDistances[0];
|
||||
|
||||
currentFeedrate = -1.0;
|
||||
|
||||
currentFeedrate = START_FEED_RATE;
|
||||
lastTime = platform->Time();
|
||||
active = true;
|
||||
}
|
||||
|
@ -171,19 +168,20 @@ void Move::Spin()
|
|||
|
||||
if(gCodes->ReadMove(nextMove, checkEndStopsOnNextMove))
|
||||
{
|
||||
if(GetMovementType(currentPosition, nextMove) == noMove)
|
||||
{
|
||||
currentFeedrate = nextMove[DRIVES]; // Might be G1 with just an F field
|
||||
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.
|
||||
return;
|
||||
}
|
||||
currentFeedrate = -1.0; // Real move - record its feedrate with it, not here.
|
||||
if(!LookAheadRingAdd(nextMove, 0.0, checkEndStopsOnNextMove))
|
||||
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[])
|
||||
{
|
||||
if(LookAheadRingFull())
|
||||
|
@ -192,11 +190,15 @@ boolean Move::GetCurrentState(float m[])
|
|||
for(int8_t i = 0; i < DRIVES; i++)
|
||||
{
|
||||
if(i < AXES)
|
||||
m[i] = currentPosition[i];
|
||||
m[i] = lastMove->EndPoint()[i];
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -233,9 +235,9 @@ boolean Move::DDARingAdd(LookAhead* lookAhead)
|
|||
ReleaseDDARingLock();
|
||||
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();
|
||||
return false;
|
||||
}
|
||||
|
@ -283,7 +285,7 @@ void Move::DoLookAhead()
|
|||
|
||||
float u, v;
|
||||
|
||||
if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > LOOK_AHEAD)
|
||||
/* if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > LOOK_AHEAD)
|
||||
{
|
||||
n1 = lookAheadRingGetPointer;
|
||||
n0 = n1->Previous();
|
||||
|
@ -330,7 +332,7 @@ void Move::DoLookAhead()
|
|||
}while(n0 != lookAheadRingGetPointer);
|
||||
n0->SetProcessed(complete);
|
||||
}
|
||||
|
||||
*/
|
||||
if(addNoMoreMoves || !gCodes->PrintingAFile() || lookAheadRingCount > 1)
|
||||
{
|
||||
n1 = lookAheadRingGetPointer;
|
||||
|
@ -340,8 +342,8 @@ void Move::DoLookAhead()
|
|||
{
|
||||
if(n1->Processed() == unprocessed)
|
||||
{
|
||||
float c = n1->Cosine();
|
||||
c = n1->EndPoint()[DRIVES]*c;
|
||||
float c = fmin(n1->EndPoint()[DRIVES], n2->EndPoint()[DRIVES]);
|
||||
c = c*n1->Cosine();
|
||||
if(c <= 0)
|
||||
{
|
||||
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
|
||||
}
|
||||
n1->SetV(c);
|
||||
n1->SetProcessed(vCosineSet);
|
||||
//n1->SetProcessed(vCosineSet);
|
||||
n1->SetProcessed(complete);
|
||||
}
|
||||
n0 = n1;
|
||||
n1 = n2;
|
||||
|
@ -403,7 +406,10 @@ boolean Move::LookAheadRingAdd(float ep[], float vv, boolean ce)
|
|||
{
|
||||
if(LookAheadRingFull())
|
||||
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);
|
||||
lastMove = lookAheadRingAddPointer;
|
||||
lookAheadRingAddPointer = lookAheadRingAddPointer->Next();
|
||||
lookAheadRingCount++;
|
||||
return true;
|
||||
|
@ -511,14 +517,15 @@ MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
|
|||
{
|
||||
int8_t drive;
|
||||
active = false;
|
||||
myLookAheadEntry = lookAhead;
|
||||
MovementProfile result = moving;
|
||||
totalSteps = -1;
|
||||
distance = 0.0; // X+Y+Z
|
||||
float eDistance = 0.0;
|
||||
float d;
|
||||
float* targetPosition = lookAhead->EndPoint();
|
||||
float* targetPosition = myLookAheadEntry->EndPoint();
|
||||
v = lookAhead->V();
|
||||
float* positionNow = lookAhead->Previous()->EndPoint();
|
||||
float* positionNow = myLookAheadEntry->Previous()->EndPoint();
|
||||
u = lookAhead->Previous()->V();
|
||||
checkEndStops = lookAhead->CheckEndStops();
|
||||
|
||||
|
@ -554,13 +561,12 @@ MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
|
|||
if(totalSteps <= 0)
|
||||
{
|
||||
platform->Message(HOST_MESSAGE, "DDA.Init(): Null movement!\n");
|
||||
myLookAheadEntry->Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Set up the DDA
|
||||
|
||||
result = moving;
|
||||
|
||||
counter[0] = -totalSteps/2;
|
||||
for(drive = 1; drive < DRIVES; drive++)
|
||||
counter[drive] = counter[0];
|
||||
|
@ -685,8 +691,6 @@ MovementProfile DDA::Init(LookAhead* lookAhead, float& u, float& v)
|
|||
|
||||
timeStep = timeStep/velocity;
|
||||
|
||||
lookAhead->Release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -729,12 +733,12 @@ void DDA::Step(boolean noTest)
|
|||
EndStopHit esh = platform->Stopped(drive);
|
||||
if(esh == lowHit)
|
||||
{
|
||||
move->HitLowStop(drive);
|
||||
move->HitLowStop(drive, myLookAheadEntry);
|
||||
active = false;
|
||||
}
|
||||
if(esh == highHit)
|
||||
{
|
||||
move->HitHighStop(drive);
|
||||
move->HitHighStop(drive, myLookAheadEntry);
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
@ -758,15 +762,18 @@ void DDA::Step(boolean noTest)
|
|||
if(stepCount >= startDStep)
|
||||
velocity -= acceleration*timeStep;
|
||||
|
||||
if(noTest)
|
||||
platform->SetInterrupt((long)(1.0e6*timeStep));
|
||||
|
||||
stepCount++;
|
||||
active = stepCount < totalSteps;
|
||||
|
||||
if(noTest)
|
||||
platform->SetInterrupt((long)(1.0e6*timeStep));
|
||||
}
|
||||
|
||||
if(!active && noTest)
|
||||
{
|
||||
myLookAheadEntry->Release();
|
||||
platform->SetInterrupt(STANDBY_INTERRUPT_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************************************
|
||||
|
|
|
@ -77,8 +77,8 @@ 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 {80, 80, 3, 25}
|
||||
#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 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
|
||||
|
|
123
README
123
README
|
@ -1,28 +1,125 @@
|
|||
This firmware is intended to be a fully object-oriented highly modular control p
|
||||
rogram for RepRap self-replicating 3D printers.
|
||||
RepRapFirmware - Main Program
|
||||
|
||||
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.
|
||||
|
||||
|
||||
General design principles:
|
||||
|
||||
* Control by RepRap G Codes. These are taken to be machine independent,
|
||||
though some may be unsupported.
|
||||
* Control by RepRap G Codes. These are taken to be machine independent, though some may be unsupported.
|
||||
* Full use of C++ OO techniques,
|
||||
* Make classes hide their data,
|
||||
* Make everything as stateless as possible,
|
||||
* No use of conditional compilation except for #include guards - if you
|
||||
need that, you should be forking the repository to make a new
|
||||
branch - let the repository take the strain,
|
||||
* Concentration of all machine-dependent defintions and code in Platform.h
|
||||
and Platform.cpp,
|
||||
* No use of conditional compilation except for #include guards - if you need that, you should be
|
||||
forking the repository to make a new branch - let the repository take the strain,
|
||||
* 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,
|
||||
* Try to be efficient in memory use, but this is not 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 avoid arrays and structs/classes,
|
||||
* Don't avoid pointers,
|
||||
* Use operator and function overloading where appropriate, particulary for
|
||||
vector algebra.
|
||||
* Use operator and function overloading where appropriate, particularly for 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
|
||||
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...
|
||||
|
||||
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
|
||||
|
||||
Started: 18 November 2012
|
||||
This date: 1 March 2013
|
||||
This date: 12 June 2013
|
||||
|
||||
Adrian Bowyer
|
||||
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
|
||||
rogram for RepRap self-replicating 3D printers.
|
||||
RepRapFirmware - Main Program
|
||||
|
||||
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.
|
||||
|
||||
|
||||
General design principles:
|
||||
|
||||
* Control by RepRap G Codes. These are taken to be machine independent,
|
||||
though some may be unsupported.
|
||||
* Control by RepRap G Codes. These are taken to be machine independent, though some may be unsupported.
|
||||
* Full use of C++ OO techniques,
|
||||
* Make classes hide their data,
|
||||
* Make everything as stateless as possible,
|
||||
* No use of conditional compilation except for #include guards - if you
|
||||
need that, you should be forking the repository to make a new
|
||||
branch - let the repository take the strain,
|
||||
* Concentration of all machine-dependent defintions and code in Platform.h
|
||||
and Platform.cpp,
|
||||
* No use of conditional compilation except for #include guards - if you need that, you should be
|
||||
forking the repository to make a new branch - let the repository take the strain,
|
||||
* 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,
|
||||
* Try to be efficient in memory use, but this is not 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 avoid arrays and structs/classes,
|
||||
* Don't avoid pointers,
|
||||
* Use operator and function overloading where appropriate, particulary for
|
||||
vector algebra.
|
||||
* Use operator and function overloading where appropriate, particularly for 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)
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
Started: 18 November 2012
|
||||
This date: 1 March 2013
|
||||
This date: 12 June 2013
|
||||
|
||||
Adrian Bowyer
|
||||
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
|
||||
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.
|
||||
|
@ -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
|
||||
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:
|
||||
|
@ -93,6 +100,26 @@ any sort of delay() function. The general rule is:
|
|||
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().
|
||||
|
||||
|
|
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