Welcome to mirror list, hosted at ThFree Co, Russian Federation.

DDA.h « Movement « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 83a8fc9ceb816b0e9d514be016646c50816ab337 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * DDA.h
 *
 *  Created on: 7 Dec 2014
 *      Author: David
 */

#ifndef DDA_H_
#define DDA_H_

#include "RepRapFirmware.h"
#include "DriveMovement.h"
#include "GCodes/GCodes.h"			// for class RawMove

#ifdef DUET_NG
#define DDA_LOG_PROBE_CHANGES	0
#else
#define DDA_LOG_PROBE_CHANGES	0		// save memory on the wired Duet
#endif

/**
 * This defines a single linear movement of the print head
 */
class DDA
{
	friend class DriveMovement;

public:

	enum DDAState : unsigned char
	{
		empty,				// empty or being filled in
		provisional,		// ready, but could be subject to modifications
		frozen,				// ready, no further modifications allowed
		executing,			// steps are currently being generated for this DDA
		completed			// move has been completed or aborted
	};

	DDA(DDA* n);

	bool Init(GCodes::RawMove &nextMove, bool doMotorMapping) __attribute__ ((hot));	// Set up a new move, returning true if it represents real movement
	bool Init(const float_t steps[DRIVES]);							// Set up a raw (unmapped) motor move
	void Init();													// Set up initial positions for machine startup
	bool Start(uint32_t tim) __attribute__ ((hot));					// Start executing the DDA, i.e. move the move.
	bool Step() __attribute__ ((hot));								// Take one step of the DDA, called by timed interrupt.
	void SetNext(DDA *n) { next = n; }
	void SetPrevious(DDA *p) { prev = p; }
	void Complete() { state = completed; }
	bool Free();
	void Prepare(uint8_t simMode) __attribute__ ((hot));			// Calculate all the values and freeze this DDA
	bool HasStepError() const;
	bool CanPauseAfter() const { return canPauseAfter; }
	bool CanPauseBefore() const { return canPauseBefore; }
	bool IsPrintingMove() const { return isPrintingMove; }			// Return true if this involves both XY movement and extrusion

	DDAState GetState() const { return state; }
	DDA* GetNext() const { return next; }
	DDA* GetPrevious() const { return prev; }
	int32_t GetTimeLeft() const;
	const int32_t *DriveCoordinates() const { return endPoint; }	// Get endpoints of a move in machine coordinates
	void SetDriveCoordinate(int32_t a, size_t drive);				// Force an end point
	void SetFeedRate(float rate) { requestedSpeed = rate; }
	float GetEndCoordinate(size_t drive, bool disableMotorMapping);
	bool FetchEndPosition(volatile int32_t ep[DRIVES], volatile float endCoords[DRIVES]);
    void SetPositions(const float move[], size_t numDrives);		// Force the endpoints to be these
    FilePosition GetFilePosition() const { return filePos; }
    float GetRequestedSpeed() const { return requestedSpeed; }
    float GetVirtualExtruderPosition() const { return virtualExtruderPosition; }
	float AdvanceBabyStepping(float amount);						// Try to push babystepping earlier in the move queue
	bool IsHomingAxes() const { return (endStopsToCheck & HomeAxes) != 0; }
	uint32_t GetXAxes() const { return xAxes; }
	uint32_t GetYAxes() const { return yAxes; }
	float GetTotalDistance() const { return totalDistance; }
	void LimitSpeedAndAcceleration(float maxSpeed, float maxAcceleration);	// Limit the speed an acceleration of this move

	int32_t GetStepsTaken(size_t drive) const;
	float GetProportionDone() const;								// Return the proportion of extrusion for the complete multi-segment move already done

	void MoveAborted();

	bool IsGoodToPrepare() const;

#if SUPPORT_IOBITS
	uint32_t GetMoveStartTime() const { return moveStartTime; }
	uint32_t GetClocksNeeded() const { return clocksNeeded; }
	IoBits_t GetIoBits() const { return ioBits; }
#endif

	void DebugPrint() const;

	static constexpr uint32_t stepClockRate = VARIANT_MCK/128;			// the frequency of the clock used for stepper pulse timing (see Platform::InitialiseInterrupts)
	static constexpr uint64_t stepClockRateSquared = (uint64_t)stepClockRate * stepClockRate;

	// Note on the following constant:
	// If we calculate the step interval on every clock, we reach a point where the calculation time exceeds the step interval.
	// The worst case is pure Z movement on a delta. On a Mini Kossel with 80 steps/mm with this firmware running on a Duet (84MHx SAM3X8 processor),
	// the calculation can just be managed in time at speeds of 15000mm/min (step interval 50us), but not at 20000mm/min (step interval 37.5us).
	// Therefore, where the step interval falls below 60us, we don't calculate on every step.
	// Note: the above measurements were taken some time ago, before some firmware optimisations.
#if SAM4E || SAM4S
	static constexpr int32_t MinCalcIntervalDelta = (40 * stepClockRate)/1000000; 		// the smallest sensible interval between calculations (40us) in step timer clocks
	static constexpr int32_t MinCalcIntervalCartesian = (40 * stepClockRate)/1000000;	// same as delta for now, but could be lower
	static constexpr uint32_t minInterruptInterval = 6;									// about 6us minimum interval between interrupts, in step clocks
#else
	static constexpr int32_t MinCalcIntervalDelta = (60 * stepClockRate)/1000000; 		// the smallest sensible interval between calculations (60us) in step timer clocks
	static constexpr int32_t MinCalcIntervalCartesian = (60 * stepClockRate)/1000000;	// same as delta for now, but could be lower
	static constexpr uint32_t minInterruptInterval = 4;									// about 6us minimum interval between interrupts, in step clocks
#endif

	static void PrintMoves();										// print saved moves for debugging

#if DDA_LOG_PROBE_CHANGES
	static const size_t MaxLoggedProbePositions = 40;
	static size_t numLoggedProbePositions;
	static int32_t loggedProbePositions[XYZ_AXES * MaxLoggedProbePositions];
#endif

	static uint32_t maxReps;

private:
	void RecalculateMove() __attribute__ ((hot));
	void CalcNewSpeeds() __attribute__ ((hot));
	void ReduceHomingSpeed();										// called to reduce homing speed when a near-endstop is triggered
	void StopDrive(size_t drive);									// stop movement of a drive and recalculate the endpoint
	void InsertDM(DriveMovement *dm) __attribute__ ((hot));
	void RemoveDM(size_t drive);
	void ReleaseDMs();
	bool IsDecelerationMove() const;								// return true if this move is or have been might have been intended to be a deceleration-only move
	void DebugPrintVector(const char *name, const float *vec, size_t len) const;
	void CheckEndstops(Platform& platform);
	float NormaliseXYZ();											// Make the direction vector unit-normal in XYZ

	static void DoLookahead(DDA *laDDA);							// Try to smooth out moves in the queue
    static float Normalise(float v[], size_t dim1, size_t dim2);  	// Normalise a vector of dim1 dimensions to unit length in the first dim1 dimensions
    static void Absolute(float v[], size_t dimensions);				// Put a vector in the positive hyperquadrant
    static float Magnitude(const float v[], size_t dimensions);  	// Return the length of a vector
    static void Scale(float v[], float scale, size_t dimensions);	// Multiply a vector by a scalar
    static float VectorBoxIntersection(const float v[], 			// Compute the length that a vector would have to have to...
    		const float box[], size_t dimensions);					// ...just touch the surface of a hyperbox.

    DDA *next;								// The next one in the ring
	DDA *prev;								// The previous one in the ring

	volatile DDAState state;				// What state this DDA is in
	uint8_t proportionRemaining;			// What proportion of the extrusion in the G1 or G0 move of which this is a part remains to be done after this segment is complete
											// - we use a uint8_t instead of a float to save space because it only affects the extrusion amount, so ~0.4% error is acceptable
	union
	{
		struct
		{
			uint8_t endCoordinatesValid : 1;		// True if endCoordinates can be relied on
			uint8_t isDeltaMovement : 1;			// True if this is a delta printer movement
			uint8_t canPauseAfter : 1;				// True if we can pause at the end of this move
			uint8_t canPauseBefore : 1;				// True if we can pause just before this move
			uint8_t isPrintingMove : 1;				// True if this move includes XY movement and extrusion
			uint8_t usePressureAdvance : 1;			// True if pressure advance should be applied to any forward extrusion
			uint8_t hadLookaheadUnderrun : 1;		// True if the lookahead queue was not long enough to optimise this move
			uint8_t xyMoving : 1;					// True if movement along an X axis or the Y axis was requested, even it if's too small to do
			uint8_t goingSlow : 1;					// True if we have slowed the movement because the Z probe is approaching its threshold
			uint8_t isLeadscrewAdjustmentMove : 1;	// True if this is a leadscrews adjustment move
		};
		uint16_t flags;								// so that we can print all the flags at once for debugging
	};

    EndstopChecks endStopsToCheck;			// Which endstops we are checking on this move
    AxesBitmap xAxes;						// Which axes are behaving as X axes
    AxesBitmap yAxes;						// Which axes are behaving as Y axes

    FilePosition filePos;					// The position in the SD card file after this move was read, or zero if not read from SD card

	int32_t endPoint[DRIVES];  				// Machine coordinates of the endpoint
	float endCoordinates[DRIVES];			// The Cartesian coordinates at the end of the move plus extrusion amounts
	float directionVector[DRIVES];			// The normalised direction vector - first 3 are XYZ Cartesian coordinates even on a delta
    float totalDistance;					// How long is the move in hypercuboid space
	float acceleration;						// The acceleration to use
    float requestedSpeed;					// The speed that the user asked for
    float virtualExtruderPosition;			// the virtual extruder position at the end of this move, used for pause/resume

    // These are used only in delta calculations
    int32_t cKc;							// The Z movement fraction multiplied by Kc and converted to integer

    // These vary depending on how we connect the move with its predecessor and successor, but remain constant while the move is being executed
	float startSpeed;
	float endSpeed;
	float topSpeed;
	float accelDistance;
	float decelDistance;

	// This is a temporary, used to keep track of the lookahead to avoid making recursive calls
	float targetNextSpeed;					// The speed that the next move would like to start at

	// These are calculated from the above and used in the ISR, so they are set up by Prepare()
	uint32_t clocksNeeded;					// in clocks
	uint32_t moveStartTime;					// clock count at which the move was started

#if SUPPORT_IOBITS
	IoBits_t ioBits;						// port state required during this move
#endif

#if DDA_LOG_PROBE_CHANGES
	static bool probeTriggered;

	void LogProbePosition();
#endif

    DriveMovement* firstDM;					// list of contained DMs that need steps, in step time order
	DriveMovement *pddm[DRIVES];			// These describe the state of each drive movement
};

// Force an end point
inline void DDA::SetDriveCoordinate(int32_t a, size_t drive)
{
	endPoint[drive] = a;
	endCoordinatesValid = false;
}

#endif /* DDA_H_ */