Plotter/plotter.cpp
2017-11-06 12:20:13 +01:00

189 lines
4.9 KiB
C++

#include "plotter.h"
const int SCALEX=2;
const int SCALEY=3;
const int BACKLASHX=20;
const int BACKLASHY=20;
template <typename T> int sgn(T val)
{
int value = (T(0) < val) - (val < T(0));
return (value == 0) ? 1 : value;
}
Plotter::Plotter(volatile unsigned char *penPort, const char penPin, Serial* serial): _pwm( &TCCR1A, &TCCR1B, &OCR1A, &OCR1B, &ICR1, 0b00000001)
{
_serial = serial;
_penPort=penPort;
_penPin=penPin;
basicposition();
}
Point Plotter::getCurrentPos()
{
return currentPos;
}
void Plotter::demo()
{
moveto(0,0);
_delay_us(200000);
moveto(32760,0);
_delay_us(200000);
moveto(32760,21840);
_delay_us(200000);
moveto(0,21840);
_delay_us(200000);
moveto(0,0);
_delay_us(200000);
pd();
pu();
}
void Plotter::basicposition()
{
moveto(0, 0);
}
void Plotter::pd()
{
if(!readPin(_penPort, _penPin))
{
_delay_us(200000);
writePin(_penPort, _penPin, true);
_delay_us(500);
}
}
void Plotter::pu()
{
if(readPin(_penPort, _penPin))
{
_delay_us(100000);
writePin(_penPort, _penPin, false);
_delay_us(500);
}
}
uint16_t Plotter::diamondAngle(int16_t y, int16_t x) //0 - 40000
{
const int32_t scalar = 10000;
if (y >= 0) return (x >= 0 ? ((int32_t)y*scalar)/(x+y) : 1*scalar-((int32_t)x*scalar)/(-x+y));
else return (x < 0 ? 2*scalar-((int32_t)y*scalar)/(-x-y) : 3*scalar+((int32_t)x*scalar)/(x-y));
}
uint16_t Plotter::calculateDelayTime(uint16_t currentDiamondAngle, uint16_t prevDiamondAngle, uint16_t prevSteps)
{
uint16_t delayTime = abs(currentDiamondAngle - prevDiamondAngle);
if ( delayTime > 20000) delayTime = delayTime - 20000;
if( prevSteps <= 4 && delayTime < 3000 ) delayTime = delayTime/5;
return delayTime;
}
void Plotter::moveRelative(int32_t deltaX, int32_t deltaY)
{
if( abs(deltaX) > 50 || abs(deltaY) > 50 )
{
if( 0 > ((deltaX+currentPos.x)*SCALEX))
{
moveto(0,deltaY+currentPos.y);
return;
}
else if( ~(uint16_t)0 <= (deltaX+currentPos.x)*SCALEX)
{
moveto(32760,deltaY+currentPos.y);
return;
}
if( 0 > (deltaY+currentPos.y)*SCALEY)
{
moveto(deltaX+currentPos.x,0);
return;
}
else if( ~(uint16_t)0 <= (deltaY+currentPos.y)*SCALEY)
{
moveto(deltaX+currentPos.x,21840);
return;
}
//delay
uint16_t currentDiamondAngle = diamondAngle(deltaX,deltaY);
uint16_t delayTime = calculateDelayTime(currentDiamondAngle, _prevDiamondAngle, _prevSteps);
if ( delayTime > 20000) delayTime = delayTime - 20000;
for (uint16_t i = 0; i < delayTime; i++) _delay_us(50);
/*//compensate backlash
if((_prevDiamondAngle < 10000 || _prevDiamondAngle > 30000 ) && deltaX < 0) deltaX = deltaX - BACKLASHX;
else if ((_prevDiamondAngle > 10000 && _prevDiamondAngle < 30000 ) && deltaX > 0) deltaX = deltaX + BACKLASHX;
if((_prevDiamondAngle < 20000) && deltaY < 0) deltaY = deltaY - BACKLASHY;
else if ((_prevDiamondAngle > 20000) && deltaY > 0) deltaY = deltaY + BACKLASHY;*/
//calculate Interporlation
uint16_t steps = 0; //one step is max 1.28205mm min 0.8547mm
int32_t StepSizeX=0;
int32_t StepSizeY=0;
if( abs(deltaX) > abs(deltaY))
{
StepSizeX = 100*sgn(deltaX);// -100
StepSizeY = (deltaY*100)/abs(deltaX); // 0
steps = deltaX/StepSizeX;
}
else
{
StepSizeX = (deltaX*100)/abs(deltaY);
StepSizeY = 100*sgn(deltaY);
steps = deltaY/StepSizeY;
}
//interpolate
for( uint16_t i = 0; i < steps; i++)
{
_pwm.setDutyA(~((uint16_t)(currentPos.x+i*StepSizeX)*SCALEX));
_pwm.setDutyB(~((uint16_t)(currentPos.y+i*StepSizeY)*SCALEY));
_delay_us(2500);
}
//set prev
_prevDiamondAngle = currentDiamondAngle;
_prevSteps = steps;
}
else
{
_delay_us(100);
}
_pwm.setDutyA(~((uint16_t)(deltaX+currentPos.x)*SCALEX));
_pwm.setDutyB(~((uint16_t)(deltaY+currentPos.y)*SCALEY));
_delay_us(3000);
if(highPrecision) _delay_us(80000);
if( abs(deltaX) > 50 || abs(deltaY) > 50 || highPrecision )
{
//set current position
currentPos.x = deltaX+currentPos.x;
currentPos.y = deltaY+currentPos.y;
}
}
void Plotter::setHighPrecision(bool in)
{
highPrecision = in;
}
void Plotter::moveto(Point *pt)
{
moveto((*pt).x,(*pt).y);
}
void Plotter::moveto(const uint16_t nx, const uint16_t ny)
{
int32_t deltaX = (int32_t)nx - (int32_t)currentPos.x; //117 units per mm
int32_t deltaY = (int32_t)ny - (int32_t)currentPos.y; //121 units per mm
moveRelative(deltaX, deltaY);
}