Use different intermediate coordinate calculation

Incremental calculation lead to high numerical errors, especially for
slow speeds.
This commit is contained in:
fruchti 2020-12-25 13:53:21 +01:00
parent 0fabe1f9d3
commit d8c9a60bd2
3 changed files with 64 additions and 43 deletions

View file

@ -1 +1 @@
250
279

View file

@ -21,9 +21,11 @@ typedef struct
unsigned int y;
} Output_Coordinate_t;
static Output_Coordinate_t Output_CurrentPoint = {0, 0};
static Output_Coordinate_t Output_TargetPoint = {0, 0};
static int Output_CurrentVelocity = 5;
static Output_Coordinate_t Output_CurrentLineStart = {0, 0};
static Output_Coordinate_t Output_CurrentLineEnd = {0, 0};
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)
{
@ -67,6 +69,28 @@ static void Output_PenUp(void)
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)
{
if(Output_BufferRead == Output_BufferWrite)
@ -89,9 +113,13 @@ static bool Output_FetchNextPoint(void)
return false;
}
Output_TargetPoint.x = movement->x;
Output_TargetPoint.y = movement->y;
// TODO: Handle pen state
Output_CurrentLineStart = Output_CurrentLineEnd;
Output_CurrentLineEnd.x = movement->x;
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++;
if(Output_BufferRead >= Output_Buffer + CONFIG_BUFFER_MOVEMENTS)
@ -101,32 +129,10 @@ static bool Output_FetchNextPoint(void)
return true;
}
static int Output_ApproximateLength(int dx, int dy)
static void Output_Position(Output_Coordinate_t position)
{
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 / 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;
uint16_t compare_x = OUTPUT_PWM_OFFSET + position.x;
uint16_t compare_y = OUTPUT_PWM_OFFSET + position.y;
TIM1->CCR1 = compare_x;
TIM1->CCR2 = compare_y;
@ -140,32 +146,42 @@ void Output_Tick(void)
return;
}
int step_length = Output_CurrentVelocity;
unsigned int step_length = Output_CurrentVelocity;
Output_Coordinate_t position;
while(true)
{
// Compute distance to current target point
int diff_x = (int)(Output_TargetPoint.x) - (int)(Output_CurrentPoint.x);
int diff_y = (int)(Output_TargetPoint.y) - (int)(Output_CurrentPoint.y);
int length_ahead = Output_ApproximateLength(diff_x, diff_y);
// Compute distance from current position to current lines end
unsigned int length_ahead = Output_CurrentLineLength
- Output_CurrentLinePosition;
if(step_length <= length_ahead)
{
// Move closer to current target point
Output_CurrentPoint.x += diff_x * step_length / length_ahead;
Output_CurrentPoint.y += diff_y * step_length / length_ahead;
// Move closer to current line end point
Output_CurrentLinePosition += step_length;
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;
}
// Current target point is not far enough away to keep velocity
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())
{
// No more points in queue, stop here
Output_CurrentPoint = Output_TargetPoint;
// No more points in queue or pen state change
break;
}
}
Output_Position();
Output_Position(position);
}
void Output_Init(void)

View file

@ -9,5 +9,10 @@
#define OUTPUT_RESOLUTION 14 // In bits
#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);
bool Output_EnqueueMovement(HPGL_Movement_t movement);