Use different intermediate coordinate calculation
Incremental calculation lead to high numerical errors, especially for slow speeds.
This commit is contained in:
parent
0fabe1f9d3
commit
d8c9a60bd2
3 changed files with 64 additions and 43 deletions
|
|
@ -1 +1 @@
|
||||||
250
|
279
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,11 @@ typedef struct
|
||||||
unsigned int y;
|
unsigned int y;
|
||||||
} Output_Coordinate_t;
|
} Output_Coordinate_t;
|
||||||
|
|
||||||
static Output_Coordinate_t Output_CurrentPoint = {0, 0};
|
static Output_Coordinate_t Output_CurrentLineStart = {0, 0};
|
||||||
static Output_Coordinate_t Output_TargetPoint = {0, 0};
|
static Output_Coordinate_t Output_CurrentLineEnd = {0, 0};
|
||||||
static int Output_CurrentVelocity = 5;
|
static unsigned int Output_CurrentLineLength;
|
||||||
|
static unsigned int Output_CurrentLinePosition;
|
||||||
|
static unsigned int Output_CurrentVelocity = OUTPUT_LENGTH_SCALE / 2;
|
||||||
|
|
||||||
bool Output_EnqueueMovement(HPGL_Movement_t movement)
|
bool Output_EnqueueMovement(HPGL_Movement_t movement)
|
||||||
{
|
{
|
||||||
|
|
@ -67,6 +69,28 @@ static void Output_PenUp(void)
|
||||||
Output_PenIsDown = false;
|
Output_PenIsDown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int Output_ApproximateLength(int dx, int dy)
|
||||||
|
{
|
||||||
|
if(dx < 0)
|
||||||
|
{
|
||||||
|
dx = -dx;
|
||||||
|
}
|
||||||
|
if(dy < 0)
|
||||||
|
{
|
||||||
|
dy = -dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Approximate vector length with alpha max plus beta min algorithm
|
||||||
|
if(dx < dy)
|
||||||
|
{
|
||||||
|
return (dy + dx) * OUTPUT_LENGTH_SCALE / 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (dx + dy) * OUTPUT_LENGTH_SCALE / 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool Output_FetchNextPoint(void)
|
static bool Output_FetchNextPoint(void)
|
||||||
{
|
{
|
||||||
if(Output_BufferRead == Output_BufferWrite)
|
if(Output_BufferRead == Output_BufferWrite)
|
||||||
|
|
@ -89,9 +113,13 @@ static bool Output_FetchNextPoint(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Output_TargetPoint.x = movement->x;
|
Output_CurrentLineStart = Output_CurrentLineEnd;
|
||||||
Output_TargetPoint.y = movement->y;
|
Output_CurrentLineEnd.x = movement->x;
|
||||||
// TODO: Handle pen state
|
Output_CurrentLineEnd.y = movement->y;
|
||||||
|
Output_CurrentLineLength = Output_ApproximateLength(
|
||||||
|
Output_CurrentLineEnd.x - Output_CurrentLineStart.x,
|
||||||
|
Output_CurrentLineEnd.y - Output_CurrentLineStart.y);
|
||||||
|
Output_CurrentLinePosition = 0;
|
||||||
|
|
||||||
Output_BufferRead++;
|
Output_BufferRead++;
|
||||||
if(Output_BufferRead >= Output_Buffer + CONFIG_BUFFER_MOVEMENTS)
|
if(Output_BufferRead >= Output_Buffer + CONFIG_BUFFER_MOVEMENTS)
|
||||||
|
|
@ -101,32 +129,10 @@ static bool Output_FetchNextPoint(void)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Output_ApproximateLength(int dx, int dy)
|
static void Output_Position(Output_Coordinate_t position)
|
||||||
{
|
{
|
||||||
if(dx < 0)
|
uint16_t compare_x = OUTPUT_PWM_OFFSET + position.x;
|
||||||
{
|
uint16_t compare_y = OUTPUT_PWM_OFFSET + position.y;
|
||||||
dx = -dx;
|
|
||||||
}
|
|
||||||
if(dy < 0)
|
|
||||||
{
|
|
||||||
dy = -dy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Approximate vector length with alpha max plus beta min algorithm
|
|
||||||
if(dx < dy)
|
|
||||||
{
|
|
||||||
return dy + dx / 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return dx + dy / 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Output_Position(void)
|
|
||||||
{
|
|
||||||
uint16_t compare_x = OUTPUT_PWM_OFFSET + Output_CurrentPoint.x;
|
|
||||||
uint16_t compare_y = OUTPUT_PWM_OFFSET + Output_CurrentPoint.y;
|
|
||||||
|
|
||||||
TIM1->CCR1 = compare_x;
|
TIM1->CCR1 = compare_x;
|
||||||
TIM1->CCR2 = compare_y;
|
TIM1->CCR2 = compare_y;
|
||||||
|
|
@ -140,32 +146,42 @@ void Output_Tick(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int step_length = Output_CurrentVelocity;
|
unsigned int step_length = Output_CurrentVelocity;
|
||||||
|
Output_Coordinate_t position;
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
// Compute distance to current target point
|
// Compute distance from current position to current line’s end
|
||||||
int diff_x = (int)(Output_TargetPoint.x) - (int)(Output_CurrentPoint.x);
|
unsigned int length_ahead = Output_CurrentLineLength
|
||||||
int diff_y = (int)(Output_TargetPoint.y) - (int)(Output_CurrentPoint.y);
|
- Output_CurrentLinePosition;
|
||||||
int length_ahead = Output_ApproximateLength(diff_x, diff_y);
|
|
||||||
if(step_length <= length_ahead)
|
if(step_length <= length_ahead)
|
||||||
{
|
{
|
||||||
// Move closer to current target point
|
// Move closer to current line end point
|
||||||
Output_CurrentPoint.x += diff_x * step_length / length_ahead;
|
Output_CurrentLinePosition += step_length;
|
||||||
Output_CurrentPoint.y += diff_y * step_length / length_ahead;
|
unsigned int remaining = Output_CurrentLineLength
|
||||||
|
- Output_CurrentLinePosition;
|
||||||
|
position.x = (Output_CurrentLineEnd.x * Output_CurrentLinePosition
|
||||||
|
+ Output_CurrentLineStart.x * remaining)
|
||||||
|
/ Output_CurrentLineLength;
|
||||||
|
position.y = (Output_CurrentLineEnd.y * Output_CurrentLinePosition
|
||||||
|
+ Output_CurrentLineStart.y * remaining)
|
||||||
|
/ Output_CurrentLineLength;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current target point is not far enough away to keep velocity
|
// Current target point is not far enough away to keep velocity
|
||||||
step_length -= length_ahead;
|
step_length -= length_ahead;
|
||||||
|
position = Output_CurrentLineEnd;
|
||||||
|
Output_CurrentLinePosition = Output_CurrentLineLength;
|
||||||
|
|
||||||
|
// Replace line start with current line end and fetch new line end
|
||||||
if(!Output_FetchNextPoint())
|
if(!Output_FetchNextPoint())
|
||||||
{
|
{
|
||||||
// No more points in queue, stop here
|
// No more points in queue or pen state change
|
||||||
Output_CurrentPoint = Output_TargetPoint;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Output_Position();
|
Output_Position(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output_Init(void)
|
void Output_Init(void)
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,10 @@
|
||||||
#define OUTPUT_RESOLUTION 14 // In bits
|
#define OUTPUT_RESOLUTION 14 // In bits
|
||||||
#define OUTPUT_COORDINATE_LIMIT ((1 << OUTPUT_RESOLUTION) - 1)
|
#define OUTPUT_COORDINATE_LIMIT ((1 << OUTPUT_RESOLUTION) - 1)
|
||||||
|
|
||||||
|
// Scale for length and velocity values to allow speeds slower than 1 axis
|
||||||
|
// resolution bit per tick. Adjust carefully as values too high can lead to
|
||||||
|
// overflows during coordinate calculations.
|
||||||
|
#define OUTPUT_LENGTH_SCALE (1 << 3)
|
||||||
|
|
||||||
void Output_Init(void);
|
void Output_Init(void);
|
||||||
bool Output_EnqueueMovement(HPGL_Movement_t movement);
|
bool Output_EnqueueMovement(HPGL_Movement_t movement);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue