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;
|
||||
} 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 line’s 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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue