Hi Tom,
I have constructed a 3D printer using the Kflop and Knozz boards. I am testing it at the moment, but I seem to be having a problem with the commanded velocity fluctuating on long paths. Also, the velocity never seems to get to the actual target velocity. I have a video (don't know how to attach that to this post) where the commanded velocity for a long straight path is 1900 mm/min but the actual velocity posted on the KMotion screen hits somewhere around 1750 and then fluctuates between about 1770 and 1740. You can hear the fluctuation in the stepper motors. I am stumped. Any suggestions?
This is a CoreXY system, so I wrote my own kinematic class using your examples. I limited the max segment length to 0.1 and I am wondering if this is causing the fluctuation. Posting my class below in case that helps.
CKinematicsCoreXY::CKinematicsCoreXY()
{
m_MotionParams.MaxLinearLength = 0.1; // limit the segment lengths for nonlinear systems
}
CKinematicsCoreXY::~CKinematicsCoreXY()
{
}
int CKinematicsCoreXY::TransformCADtoActuators(double x, double y, double z, double a, double b, double c, double *Acts, bool NoGeo)
{
// find motor counts of each actuator
GeoCorrect(x,y,z,&x,&y,&z);
Acts[0] = (x + y)*m_MotionParams.CountsPerInchX;
Acts[1] = (x - y)*m_MotionParams.CountsPerInchY;
Acts[2] = z*m_MotionParams.CountsPerInchZ;
Acts[3] = a*m_MotionParams.CountsPerInchA;
Acts[4] = b*m_MotionParams.CountsPerInchB;
Acts[5] = c*m_MotionParams.CountsPerInchC;
return 0;
}
// perform Inversion to go the other way
int CKinematicsCoreXY::TransformActuatorstoCAD(double *Acts, double *xr, double *yr, double *zr, double *ar, double *br, double *cr, bool NoGeo)
{
return InvertTransformCADtoActuators(Acts, xr, yr, zr, ar, br, cr);
}
Commanded velocity seems to be fluctuating
Moderators: TomKerekes, dynomotion
- TomKerekes
- Posts: 2679
- Joined: Mon Dec 04, 2017 1:49 am
Re: Commanded velocity seems to be fluctuating
KFLOP automatically slows down the feed rate if it determines there is too little buffered motion data and where it may not be possible stop before running out of data. KFLOP examines the Axis parameters to determine the maximum amount of time to stop.
The Trajectory Planner Lookahead Time limits how much motion can be buffered.
So one possibility is that one or more set of Axis parameters are configured such that a worst case stop would take an unusually long time. A common problem is to set a crazy high Velocity or Acceleration that would never be normally achieved because of other constraints.
Please post your Initialization C Program and your Trajectory Planner Settings.
The Trajectory Planner Lookahead Time limits how much motion can be buffered.
So one possibility is that one or more set of Axis parameters are configured such that a worst case stop would take an unusually long time. A common problem is to set a crazy high Velocity or Acceleration that would never be normally achieved because of other constraints.
Please post your Initialization C Program and your Trajectory Planner Settings.
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
Re: Commanded velocity seems to be fluctuating
Interesting. If I wanted to use a high acceleration, are there ways of going about tuning the look ahead to deal with that? Acceleration is one of the things I want out of this platform.
#include "KMotionDef.h"
// A KMotionCNC MCode can be configured to set the temperature setpoints
// using P and Q parameters. ie.
// M100 P100 Q50 (Set Nozzle and Bed temperature setpoints)
#define AUX 0 // 0=Aux0 1=Aux1 defines which Aux connector to use.
// define pair of persist variables (as floats) as heater setpoints
#define NOZ_VAR 30
#define BED_VAR (NOZ_VAR+1)
#define NOZ_CURRENT (NOZ_VAR+2)
#define BED_CURRENT (NOZ_VAR+3)
//SPI and Heater IO definitions
#define CS (23 + AUX*10)
#define DATAIN (24 + AUX*10) // with respect to KFLOP
#define CLK (25 + AUX*10)
#define DOUT (22 + AUX*10) // with respect to KFLOP
#define NOZ_HEAT (21 + AUX*10)
#define BED_HEAT (20 + AUX*10)
int SPI_IN(int send_data); // function to read serial SPI dual ADC
float TempToADC(float T); // function to convert Temp C to ADC counts
float ADCtoTemp(float At);// Solve inverse function numerically using guesses and linear interpolate
void ServiceKNozz(void); // Service KNozz Temperature controls
float *NozSetPoint = (float *)&persist.UserData[NOZ_VAR]; // define convienient pointers to Persist floats
float *BedSetPoint = (float *)&persist.UserData[BED_VAR];
float *NozTemp = (float *)&persist.UserData[NOZ_CURRENT];
float *BedTemp = (float *)&persist.UserData[BED_CURRENT];
int main()
{
ch0->InputMode=NO_INPUT_MODE;
ch0->OutputMode=STEP_DIR_MODE;
ch0->Vel=23707;
ch0->Accel=711200;
ch0->Jerk=10000000;
ch0->P=1;
ch0->I=0;
ch0->D=0;
ch0->FFAccel=0;
ch0->FFVel=0;
ch0->MaxI=200;
ch0->MaxErr=1000;
ch0->MaxOutput=200;
ch0->DeadBandGain=1;
ch0->DeadBandRange=0;
ch0->InputChan0=0;
ch0->InputChan1=0;
ch0->OutputChan0=8;
ch0->OutputChan1=1;
ch0->MasterAxis=-1;
ch0->LimitSwitchOptions=0x110;
ch0->LimitSwitchNegBit=19;
ch0->LimitSwitchPosBit=20;
ch0->SoftLimitPos=1e+30;
ch0->SoftLimitNeg=-1e+30;
ch0->InputGain0=1;
ch0->InputGain1=1;
ch0->InputOffset0=0;
ch0->InputOffset1=0;
ch0->OutputGain=1;
ch0->OutputOffset=0;
ch0->SlaveGain=1;
ch0->BacklashMode=BACKLASH_OFF;
ch0->BacklashAmount=0;
ch0->BacklashRate=0;
ch0->invDistPerCycle=1;
ch0->Lead=0;
ch0->MaxFollowingError=1000;
ch0->StepperAmplitude=20;
ch0->iir[0].B0=1;
ch0->iir[0].B1=0;
ch0->iir[0].B2=0;
ch0->iir[0].A1=0;
ch0->iir[0].A2=0;
ch0->iir[1].B0=1;
ch0->iir[1].B1=0;
ch0->iir[1].B2=0;
ch0->iir[1].A1=0;
ch0->iir[1].A2=0;
ch0->iir[2].B0=1;
ch0->iir[2].B1=0;
ch0->iir[2].B2=0;
ch0->iir[2].A1=0;
ch0->iir[2].A2=0;
ch1->InputMode=NO_INPUT_MODE;
ch1->OutputMode=STEP_DIR_MODE;
ch1->Vel=23707;
ch1->Accel=711200;
ch1->Jerk=10000000;
ch1->P=1;
ch1->I=0;
ch1->D=0;
ch1->FFAccel=0;
ch1->FFVel=0;
ch1->MaxI=200;
ch1->MaxErr=1e+06;
ch1->MaxOutput=200;
ch1->DeadBandGain=1;
ch1->DeadBandRange=0;
ch1->InputChan0=1;
ch1->InputChan1=1;
ch1->OutputChan0=9;
ch1->OutputChan1=3;
ch1->MasterAxis=-1;
ch1->LimitSwitchOptions=0x110;
ch1->LimitSwitchNegBit=0;
ch1->LimitSwitchPosBit=0;
ch1->SoftLimitPos=1e+30;
ch1->SoftLimitNeg=-1e+30;
ch1->InputGain0=1;
ch1->InputGain1=1;
ch1->InputOffset0=0;
ch1->InputOffset1=0;
ch1->OutputGain=1;
ch1->OutputOffset=0;
ch1->SlaveGain=1;
ch1->BacklashMode=BACKLASH_OFF;
ch1->BacklashAmount=7;
ch1->BacklashRate=4000;
ch1->invDistPerCycle=4;
ch1->Lead=0;
ch1->MaxFollowingError=1000;
ch1->StepperAmplitude=20;
ch1->iir[0].B0=1;
ch1->iir[0].B1=0;
ch1->iir[0].B2=0;
ch1->iir[0].A1=0;
ch1->iir[0].A2=0;
ch1->iir[1].B0=1;
ch1->iir[1].B1=0;
ch1->iir[1].B2=0;
ch1->iir[1].A1=0;
ch1->iir[1].A2=0;
ch1->iir[2].B0=1;
ch1->iir[2].B1=0;
ch1->iir[2].B2=0;
ch1->iir[2].A1=0;
ch1->iir[2].A2=0;
ch2->InputMode=NO_INPUT_MODE;
ch2->OutputMode=STEP_DIR_MODE;
ch2->Vel=30480;
ch2->Accel=304800;
ch2->Jerk=3048000;
ch2->P=1;
ch2->I=0;
ch2->D=0;
ch2->FFAccel=0;
ch2->FFVel=0;
ch2->MaxI=200;
ch2->MaxErr=1e+06;
ch2->MaxOutput=200;
ch2->DeadBandGain=1;
ch2->DeadBandRange=0;
ch2->InputChan0=2;
ch2->InputChan1=2;
ch2->OutputChan0=10;
ch2->OutputChan1=5;
ch2->MasterAxis=-1;
ch2->LimitSwitchOptions=0x110;
ch2->LimitSwitchNegBit=0;
ch2->LimitSwitchPosBit=0;
ch2->SoftLimitPos=1e+30;
ch2->SoftLimitNeg=-1e+30;
ch2->InputGain0=1;
ch2->InputGain1=1;
ch2->InputOffset0=0;
ch2->InputOffset1=0;
ch2->OutputGain=1;
ch2->OutputOffset=0;
ch2->SlaveGain=1;
ch2->BacklashMode=BACKLASH_OFF;
ch2->BacklashAmount=0;
ch2->BacklashRate=8200;
ch2->invDistPerCycle=1;
ch2->Lead=0;
ch2->MaxFollowingError=1000;
ch2->StepperAmplitude=20;
ch2->iir[0].B0=1;
ch2->iir[0].B1=0;
ch2->iir[0].B2=0;
ch2->iir[0].A1=0;
ch2->iir[0].A2=0;
ch2->iir[1].B0=1;
ch2->iir[1].B1=0;
ch2->iir[1].B2=0;
ch2->iir[1].A1=0;
ch2->iir[1].A2=0;
ch2->iir[2].B0=1;
ch2->iir[2].B1=0;
ch2->iir[2].B2=0;
ch2->iir[2].A1=0;
ch2->iir[2].A2=0;
ch3->InputMode=NO_INPUT_MODE;
ch3->OutputMode=STEP_DIR_MODE;
ch3->Vel=40000;
ch3->Accel=400000;
ch3->Jerk=4e+06;
ch3->P=1;
ch3->I=0;
ch3->D=0;
ch3->FFAccel=0;
ch3->FFVel=0;
ch3->MaxI=200;
ch3->MaxErr=1e+06;
ch3->MaxOutput=200;
ch3->DeadBandGain=1;
ch3->DeadBandRange=0;
ch3->InputChan0=3;
ch3->InputChan1=0;
ch3->OutputChan0=11;
ch3->OutputChan1=0;
ch3->MasterAxis=-1;
ch3->LimitSwitchOptions=0x110;
ch3->LimitSwitchNegBit=0;
ch3->LimitSwitchPosBit=0;
ch3->SoftLimitPos=1e+30;
ch3->SoftLimitNeg=-1e+30;
ch3->InputGain0=1;
ch3->InputGain1=1;
ch3->InputOffset0=0;
ch3->InputOffset1=0;
ch3->OutputGain=-1;
ch3->OutputOffset=0;
ch3->SlaveGain=1;
ch3->BacklashMode=BACKLASH_OFF;
ch3->BacklashAmount=0;
ch3->BacklashRate=0;
ch3->invDistPerCycle=1;
ch3->Lead=0;
ch3->MaxFollowingError=10000;
ch3->StepperAmplitude=20;
ch3->iir[0].B0=1;
ch3->iir[0].B1=0;
ch3->iir[0].B2=0;
ch3->iir[0].A1=0;
ch3->iir[0].A2=0;
ch3->iir[1].B0=1;
ch3->iir[1].B1=0;
ch3->iir[1].B2=0;
ch3->iir[1].A1=0;
ch3->iir[1].A2=0;
ch3->iir[2].B0=1;
ch3->iir[2].B1=0;
ch3->iir[2].B2=0;
ch3->iir[2].A1=0;
ch3->iir[2].A2=0;
ch4->InputMode=NO_INPUT_MODE;
ch4->OutputMode=STEP_DIR_MODE;
ch4->Vel=5420;;
ch4->Accel=4000;
ch4->Jerk=40000;
ch4->P=1;
ch4->I=0;
ch4->D=0;
ch4->FFAccel=0;
ch4->FFVel=0;
ch4->MaxI=200;
ch4->MaxErr=200;
ch4->MaxOutput=200;
ch4->DeadBandGain=1;
ch4->DeadBandRange=0;
ch4->InputChan0=4;
ch4->InputChan1=0;
ch4->OutputChan0=12;
ch4->OutputChan1=0;
ch4->MasterAxis=-1;
ch4->LimitSwitchOptions=0x100;
ch4->LimitSwitchNegBit=0;
ch4->LimitSwitchPosBit=0;
ch4->SoftLimitPos=1e+09;
ch4->SoftLimitNeg=-1e+09;
ch4->InputGain0=1;
ch4->InputGain1=1;
ch4->InputOffset0=0;
ch4->InputOffset1=0;
ch4->OutputGain=1;
ch4->OutputOffset=0;
ch4->SlaveGain=1;
ch4->BacklashMode=BACKLASH_OFF;
ch4->BacklashAmount=0;
ch4->BacklashRate=0;
ch4->invDistPerCycle=1;
ch4->Lead=0;
ch4->MaxFollowingError=10000000;
ch4->StepperAmplitude=250;
ch4->iir[0].B0=1;
ch4->iir[0].B1=0;
ch4->iir[0].B2=0;
ch4->iir[0].A1=0;
ch4->iir[0].A2=0;
ch4->iir[1].B0=1;
ch4->iir[1].B1=0;
ch4->iir[1].B2=0;
ch4->iir[1].A1=0;
ch4->iir[1].A2=0;
ch4->iir[2].B0=1;
ch4->iir[2].B1=0;
ch4->iir[2].B2=0;
ch4->iir[2].A1=0;
ch4->iir[2].A2=0;
EnableAxis(0);
EnableAxis(1);
EnableAxis(2);
EnableAxis(3);
EnableAxis(4);
DefineCoordSystem6(1,0,2,3,4,-1);
//DefineCoordSystem(1,0,2,-1);
SetBitDirection(CS, 1);
SetBitDirection(CLK, 1);
SetBitDirection(NOZ_HEAT, 1);
SetBitDirection(DOUT, 1);
SetBitDirection(BED_HEAT, 1);
*NozSetPoint = 0; // start with heaters off
*BedSetPoint = 0;
*NozTemp = 0;
*BedTemp = 0;
for (;;)
{
Delay_sec(0.001); // loop ~every millisecond
ServiceKNozz();
}
return 0;
}
// Service KNozz Temperature controls
void ServiceKNozz(void)
{
static int JobWasActive = FALSE;
static int i = 0;
int raw_counts_bed = SPI_IN(0xf000); // Read ADCs
int raw_counts_noz = SPI_IN(0xd000);
float NTempFloat = ADCtoTemp(raw_counts_noz);
float BTempFloat = ADCtoTemp(raw_counts_bed);
persist.UserData[NOZ_CURRENT] = *(int *) & NTempFloat;
persist.UserData[BED_CURRENT] = *(int *) & BTempFloat;
if (i++ >= 5000) // diagnostic printout ~ every 1 sec
{
i = 0;
printf("Nozz:Setpt %6.1fC %6.1fcnts Actual %6.1fC %4dcnts Bed:Setpt %6.1fC %6.1fcnts Actual %6.1fC %4dcnts\n",
*NozSetPoint, TempToADC(*NozSetPoint), ADCtoTemp(raw_counts_noz), raw_counts_noz,
*BedSetPoint, TempToADC(*BedSetPoint), ADCtoTemp(raw_counts_bed), raw_counts_bed);
}
if (raw_counts_noz < TempToADC(*NozSetPoint))
SetBit(NOZ_HEAT);
else
ClearBit(NOZ_HEAT);
if (raw_counts_bed < TempToADC(*BedSetPoint))
SetBit(BED_HEAT);
else
ClearBit(BED_HEAT);
if (JobWasActive && !JOB_ACTIVE) // Job Stopped?
{
// *NozSetPoint=0; // yes, turn off heater?
// *BedSetPoint=0;
}
JobWasActive = JOB_ACTIVE;
}
void Dly(void)
{
Delay_sec(5e-6);
}
int SPI_IN(int send_data)
{
int i;
int dataIn = 0;
SetBit(CS); //CS high
Dly();
ClearBit(CLK); //CLK low
Dly();
ClearBit(CS); //CS low
SetStateBit(DOUT, (send_data >> 15) & 1);
Dly();
for (i = 0; i < 16; i++)
{
SetBit(CLK); //CLK high
Dly();
dataIn = (dataIn << 1) | ReadBit(DATAIN); // read the bit
ClearBit(CLK); //CLK low
SetStateBit(DOUT, (send_data >> (14 - i)) & 1);
Dly();
}
SetBit(CS); //CS high
Dly();
return dataIn;
}
// Convert Temperature in C to equivalent ADC Counts
// based on 3rd order data fit to this measured data
//
// Temp C, ADC
// 16.0 199
// 35.0 400
// 49.1 600
// 54.7 700
// 60.7 800
// 66.9 900
// 73.6 1000
// 78.4 1100
// 85.2 1200
// 93.8 1300
//107.5 1482
//115.5 1570
//125.0 1688
//132.0 1722
// function to convert Temp C to ADC counts
float TempToADC(float T)
{
return (((0.0008855153784 - 0.000000824412405 * T) * T - 0.3469344589) * T + 59.42378307)*T - 1767.00037; // 3rd order polynomial
//return T;
}
// Solve inverse function numerically using guesses and linear interpolate
float ADCtoTemp(float At)
{
int i;
float A, T, T0 = 40.0, T1 = 100.0; // initial guess 0 snd 1
float A0 = TempToADC(T0); // see how well they did
float A1 = TempToADC(T1);
for (i = 0; i < 10; i++)
{
// linearly interpolate
T = T0 + (T1 - T0) * (At - A0) / (A1 - A0);
A = TempToADC(T); // check how well it works
// printf("Desired ADC %f guess Temp %f ADC %f\n",At,T,A);
if (fast_fabs(A - At) < 0.1f) break; // good result exit
// replace furthest away guess with new result
if (fast_fabs(A - A0) > fast_fabs(A - A1))
{
T0 = T;// replace guess #0
A0 = A;
}
else
{
T1 = T;// replace guess #1
A1 = A;
}
}
return T;
}
#include "KMotionDef.h"
// A KMotionCNC MCode can be configured to set the temperature setpoints
// using P and Q parameters. ie.
// M100 P100 Q50 (Set Nozzle and Bed temperature setpoints)
#define AUX 0 // 0=Aux0 1=Aux1 defines which Aux connector to use.
// define pair of persist variables (as floats) as heater setpoints
#define NOZ_VAR 30
#define BED_VAR (NOZ_VAR+1)
#define NOZ_CURRENT (NOZ_VAR+2)
#define BED_CURRENT (NOZ_VAR+3)
//SPI and Heater IO definitions
#define CS (23 + AUX*10)
#define DATAIN (24 + AUX*10) // with respect to KFLOP
#define CLK (25 + AUX*10)
#define DOUT (22 + AUX*10) // with respect to KFLOP
#define NOZ_HEAT (21 + AUX*10)
#define BED_HEAT (20 + AUX*10)
int SPI_IN(int send_data); // function to read serial SPI dual ADC
float TempToADC(float T); // function to convert Temp C to ADC counts
float ADCtoTemp(float At);// Solve inverse function numerically using guesses and linear interpolate
void ServiceKNozz(void); // Service KNozz Temperature controls
float *NozSetPoint = (float *)&persist.UserData[NOZ_VAR]; // define convienient pointers to Persist floats
float *BedSetPoint = (float *)&persist.UserData[BED_VAR];
float *NozTemp = (float *)&persist.UserData[NOZ_CURRENT];
float *BedTemp = (float *)&persist.UserData[BED_CURRENT];
int main()
{
ch0->InputMode=NO_INPUT_MODE;
ch0->OutputMode=STEP_DIR_MODE;
ch0->Vel=23707;
ch0->Accel=711200;
ch0->Jerk=10000000;
ch0->P=1;
ch0->I=0;
ch0->D=0;
ch0->FFAccel=0;
ch0->FFVel=0;
ch0->MaxI=200;
ch0->MaxErr=1000;
ch0->MaxOutput=200;
ch0->DeadBandGain=1;
ch0->DeadBandRange=0;
ch0->InputChan0=0;
ch0->InputChan1=0;
ch0->OutputChan0=8;
ch0->OutputChan1=1;
ch0->MasterAxis=-1;
ch0->LimitSwitchOptions=0x110;
ch0->LimitSwitchNegBit=19;
ch0->LimitSwitchPosBit=20;
ch0->SoftLimitPos=1e+30;
ch0->SoftLimitNeg=-1e+30;
ch0->InputGain0=1;
ch0->InputGain1=1;
ch0->InputOffset0=0;
ch0->InputOffset1=0;
ch0->OutputGain=1;
ch0->OutputOffset=0;
ch0->SlaveGain=1;
ch0->BacklashMode=BACKLASH_OFF;
ch0->BacklashAmount=0;
ch0->BacklashRate=0;
ch0->invDistPerCycle=1;
ch0->Lead=0;
ch0->MaxFollowingError=1000;
ch0->StepperAmplitude=20;
ch0->iir[0].B0=1;
ch0->iir[0].B1=0;
ch0->iir[0].B2=0;
ch0->iir[0].A1=0;
ch0->iir[0].A2=0;
ch0->iir[1].B0=1;
ch0->iir[1].B1=0;
ch0->iir[1].B2=0;
ch0->iir[1].A1=0;
ch0->iir[1].A2=0;
ch0->iir[2].B0=1;
ch0->iir[2].B1=0;
ch0->iir[2].B2=0;
ch0->iir[2].A1=0;
ch0->iir[2].A2=0;
ch1->InputMode=NO_INPUT_MODE;
ch1->OutputMode=STEP_DIR_MODE;
ch1->Vel=23707;
ch1->Accel=711200;
ch1->Jerk=10000000;
ch1->P=1;
ch1->I=0;
ch1->D=0;
ch1->FFAccel=0;
ch1->FFVel=0;
ch1->MaxI=200;
ch1->MaxErr=1e+06;
ch1->MaxOutput=200;
ch1->DeadBandGain=1;
ch1->DeadBandRange=0;
ch1->InputChan0=1;
ch1->InputChan1=1;
ch1->OutputChan0=9;
ch1->OutputChan1=3;
ch1->MasterAxis=-1;
ch1->LimitSwitchOptions=0x110;
ch1->LimitSwitchNegBit=0;
ch1->LimitSwitchPosBit=0;
ch1->SoftLimitPos=1e+30;
ch1->SoftLimitNeg=-1e+30;
ch1->InputGain0=1;
ch1->InputGain1=1;
ch1->InputOffset0=0;
ch1->InputOffset1=0;
ch1->OutputGain=1;
ch1->OutputOffset=0;
ch1->SlaveGain=1;
ch1->BacklashMode=BACKLASH_OFF;
ch1->BacklashAmount=7;
ch1->BacklashRate=4000;
ch1->invDistPerCycle=4;
ch1->Lead=0;
ch1->MaxFollowingError=1000;
ch1->StepperAmplitude=20;
ch1->iir[0].B0=1;
ch1->iir[0].B1=0;
ch1->iir[0].B2=0;
ch1->iir[0].A1=0;
ch1->iir[0].A2=0;
ch1->iir[1].B0=1;
ch1->iir[1].B1=0;
ch1->iir[1].B2=0;
ch1->iir[1].A1=0;
ch1->iir[1].A2=0;
ch1->iir[2].B0=1;
ch1->iir[2].B1=0;
ch1->iir[2].B2=0;
ch1->iir[2].A1=0;
ch1->iir[2].A2=0;
ch2->InputMode=NO_INPUT_MODE;
ch2->OutputMode=STEP_DIR_MODE;
ch2->Vel=30480;
ch2->Accel=304800;
ch2->Jerk=3048000;
ch2->P=1;
ch2->I=0;
ch2->D=0;
ch2->FFAccel=0;
ch2->FFVel=0;
ch2->MaxI=200;
ch2->MaxErr=1e+06;
ch2->MaxOutput=200;
ch2->DeadBandGain=1;
ch2->DeadBandRange=0;
ch2->InputChan0=2;
ch2->InputChan1=2;
ch2->OutputChan0=10;
ch2->OutputChan1=5;
ch2->MasterAxis=-1;
ch2->LimitSwitchOptions=0x110;
ch2->LimitSwitchNegBit=0;
ch2->LimitSwitchPosBit=0;
ch2->SoftLimitPos=1e+30;
ch2->SoftLimitNeg=-1e+30;
ch2->InputGain0=1;
ch2->InputGain1=1;
ch2->InputOffset0=0;
ch2->InputOffset1=0;
ch2->OutputGain=1;
ch2->OutputOffset=0;
ch2->SlaveGain=1;
ch2->BacklashMode=BACKLASH_OFF;
ch2->BacklashAmount=0;
ch2->BacklashRate=8200;
ch2->invDistPerCycle=1;
ch2->Lead=0;
ch2->MaxFollowingError=1000;
ch2->StepperAmplitude=20;
ch2->iir[0].B0=1;
ch2->iir[0].B1=0;
ch2->iir[0].B2=0;
ch2->iir[0].A1=0;
ch2->iir[0].A2=0;
ch2->iir[1].B0=1;
ch2->iir[1].B1=0;
ch2->iir[1].B2=0;
ch2->iir[1].A1=0;
ch2->iir[1].A2=0;
ch2->iir[2].B0=1;
ch2->iir[2].B1=0;
ch2->iir[2].B2=0;
ch2->iir[2].A1=0;
ch2->iir[2].A2=0;
ch3->InputMode=NO_INPUT_MODE;
ch3->OutputMode=STEP_DIR_MODE;
ch3->Vel=40000;
ch3->Accel=400000;
ch3->Jerk=4e+06;
ch3->P=1;
ch3->I=0;
ch3->D=0;
ch3->FFAccel=0;
ch3->FFVel=0;
ch3->MaxI=200;
ch3->MaxErr=1e+06;
ch3->MaxOutput=200;
ch3->DeadBandGain=1;
ch3->DeadBandRange=0;
ch3->InputChan0=3;
ch3->InputChan1=0;
ch3->OutputChan0=11;
ch3->OutputChan1=0;
ch3->MasterAxis=-1;
ch3->LimitSwitchOptions=0x110;
ch3->LimitSwitchNegBit=0;
ch3->LimitSwitchPosBit=0;
ch3->SoftLimitPos=1e+30;
ch3->SoftLimitNeg=-1e+30;
ch3->InputGain0=1;
ch3->InputGain1=1;
ch3->InputOffset0=0;
ch3->InputOffset1=0;
ch3->OutputGain=-1;
ch3->OutputOffset=0;
ch3->SlaveGain=1;
ch3->BacklashMode=BACKLASH_OFF;
ch3->BacklashAmount=0;
ch3->BacklashRate=0;
ch3->invDistPerCycle=1;
ch3->Lead=0;
ch3->MaxFollowingError=10000;
ch3->StepperAmplitude=20;
ch3->iir[0].B0=1;
ch3->iir[0].B1=0;
ch3->iir[0].B2=0;
ch3->iir[0].A1=0;
ch3->iir[0].A2=0;
ch3->iir[1].B0=1;
ch3->iir[1].B1=0;
ch3->iir[1].B2=0;
ch3->iir[1].A1=0;
ch3->iir[1].A2=0;
ch3->iir[2].B0=1;
ch3->iir[2].B1=0;
ch3->iir[2].B2=0;
ch3->iir[2].A1=0;
ch3->iir[2].A2=0;
ch4->InputMode=NO_INPUT_MODE;
ch4->OutputMode=STEP_DIR_MODE;
ch4->Vel=5420;;
ch4->Accel=4000;
ch4->Jerk=40000;
ch4->P=1;
ch4->I=0;
ch4->D=0;
ch4->FFAccel=0;
ch4->FFVel=0;
ch4->MaxI=200;
ch4->MaxErr=200;
ch4->MaxOutput=200;
ch4->DeadBandGain=1;
ch4->DeadBandRange=0;
ch4->InputChan0=4;
ch4->InputChan1=0;
ch4->OutputChan0=12;
ch4->OutputChan1=0;
ch4->MasterAxis=-1;
ch4->LimitSwitchOptions=0x100;
ch4->LimitSwitchNegBit=0;
ch4->LimitSwitchPosBit=0;
ch4->SoftLimitPos=1e+09;
ch4->SoftLimitNeg=-1e+09;
ch4->InputGain0=1;
ch4->InputGain1=1;
ch4->InputOffset0=0;
ch4->InputOffset1=0;
ch4->OutputGain=1;
ch4->OutputOffset=0;
ch4->SlaveGain=1;
ch4->BacklashMode=BACKLASH_OFF;
ch4->BacklashAmount=0;
ch4->BacklashRate=0;
ch4->invDistPerCycle=1;
ch4->Lead=0;
ch4->MaxFollowingError=10000000;
ch4->StepperAmplitude=250;
ch4->iir[0].B0=1;
ch4->iir[0].B1=0;
ch4->iir[0].B2=0;
ch4->iir[0].A1=0;
ch4->iir[0].A2=0;
ch4->iir[1].B0=1;
ch4->iir[1].B1=0;
ch4->iir[1].B2=0;
ch4->iir[1].A1=0;
ch4->iir[1].A2=0;
ch4->iir[2].B0=1;
ch4->iir[2].B1=0;
ch4->iir[2].B2=0;
ch4->iir[2].A1=0;
ch4->iir[2].A2=0;
EnableAxis(0);
EnableAxis(1);
EnableAxis(2);
EnableAxis(3);
EnableAxis(4);
DefineCoordSystem6(1,0,2,3,4,-1);
//DefineCoordSystem(1,0,2,-1);
SetBitDirection(CS, 1);
SetBitDirection(CLK, 1);
SetBitDirection(NOZ_HEAT, 1);
SetBitDirection(DOUT, 1);
SetBitDirection(BED_HEAT, 1);
*NozSetPoint = 0; // start with heaters off
*BedSetPoint = 0;
*NozTemp = 0;
*BedTemp = 0;
for (;;)
{
Delay_sec(0.001); // loop ~every millisecond
ServiceKNozz();
}
return 0;
}
// Service KNozz Temperature controls
void ServiceKNozz(void)
{
static int JobWasActive = FALSE;
static int i = 0;
int raw_counts_bed = SPI_IN(0xf000); // Read ADCs
int raw_counts_noz = SPI_IN(0xd000);
float NTempFloat = ADCtoTemp(raw_counts_noz);
float BTempFloat = ADCtoTemp(raw_counts_bed);
persist.UserData[NOZ_CURRENT] = *(int *) & NTempFloat;
persist.UserData[BED_CURRENT] = *(int *) & BTempFloat;
if (i++ >= 5000) // diagnostic printout ~ every 1 sec
{
i = 0;
printf("Nozz:Setpt %6.1fC %6.1fcnts Actual %6.1fC %4dcnts Bed:Setpt %6.1fC %6.1fcnts Actual %6.1fC %4dcnts\n",
*NozSetPoint, TempToADC(*NozSetPoint), ADCtoTemp(raw_counts_noz), raw_counts_noz,
*BedSetPoint, TempToADC(*BedSetPoint), ADCtoTemp(raw_counts_bed), raw_counts_bed);
}
if (raw_counts_noz < TempToADC(*NozSetPoint))
SetBit(NOZ_HEAT);
else
ClearBit(NOZ_HEAT);
if (raw_counts_bed < TempToADC(*BedSetPoint))
SetBit(BED_HEAT);
else
ClearBit(BED_HEAT);
if (JobWasActive && !JOB_ACTIVE) // Job Stopped?
{
// *NozSetPoint=0; // yes, turn off heater?
// *BedSetPoint=0;
}
JobWasActive = JOB_ACTIVE;
}
void Dly(void)
{
Delay_sec(5e-6);
}
int SPI_IN(int send_data)
{
int i;
int dataIn = 0;
SetBit(CS); //CS high
Dly();
ClearBit(CLK); //CLK low
Dly();
ClearBit(CS); //CS low
SetStateBit(DOUT, (send_data >> 15) & 1);
Dly();
for (i = 0; i < 16; i++)
{
SetBit(CLK); //CLK high
Dly();
dataIn = (dataIn << 1) | ReadBit(DATAIN); // read the bit
ClearBit(CLK); //CLK low
SetStateBit(DOUT, (send_data >> (14 - i)) & 1);
Dly();
}
SetBit(CS); //CS high
Dly();
return dataIn;
}
// Convert Temperature in C to equivalent ADC Counts
// based on 3rd order data fit to this measured data
//
// Temp C, ADC
// 16.0 199
// 35.0 400
// 49.1 600
// 54.7 700
// 60.7 800
// 66.9 900
// 73.6 1000
// 78.4 1100
// 85.2 1200
// 93.8 1300
//107.5 1482
//115.5 1570
//125.0 1688
//132.0 1722
// function to convert Temp C to ADC counts
float TempToADC(float T)
{
return (((0.0008855153784 - 0.000000824412405 * T) * T - 0.3469344589) * T + 59.42378307)*T - 1767.00037; // 3rd order polynomial
//return T;
}
// Solve inverse function numerically using guesses and linear interpolate
float ADCtoTemp(float At)
{
int i;
float A, T, T0 = 40.0, T1 = 100.0; // initial guess 0 snd 1
float A0 = TempToADC(T0); // see how well they did
float A1 = TempToADC(T1);
for (i = 0; i < 10; i++)
{
// linearly interpolate
T = T0 + (T1 - T0) * (At - A0) / (A1 - A0);
A = TempToADC(T); // check how well it works
// printf("Desired ADC %f guess Temp %f ADC %f\n",At,T,A);
if (fast_fabs(A - At) < 0.1f) break; // good result exit
// replace furthest away guess with new result
if (fast_fabs(A - A0) > fast_fabs(A - A1))
{
T0 = T;// replace guess #0
A0 = A;
}
else
{
T1 = T;// replace guess #1
A1 = A;
}
}
return T;
}
- TomKerekes
- Posts: 2679
- Joined: Mon Dec 04, 2017 1:49 am
Re: Commanded velocity seems to be fluctuating
Hi tarober,
I think the issue might be the low acceleration of Axis 4. That would take more than 5420/4000 = 1.355 seconds to stop. Does the Acceleration need to be so low?
I think the issue might be the low acceleration of Axis 4. That would take more than 5420/4000 = 1.355 seconds to stop. Does the Acceleration need to be so low?
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
Re: Commanded velocity seems to be fluctuating
Nope, it is actually an auxillary motion, so not even used while printing is happening. I will turn it up and give it a shot. Thanks for the help. If this solves it, I know I would never have figured that out on my own.
- TomKerekes
- Posts: 2679
- Joined: Mon Dec 04, 2017 1:49 am
Re: Commanded velocity seems to be fluctuating
btw I think your Kinematics are Linear. A straight line in CAD space will be a straight line in actuator space, so there shouldn't be any need to limit the lengths of linear segments.
Regards,
Tom Kerekes
Dynomotion, Inc.
Tom Kerekes
Dynomotion, Inc.
Re: Commanded velocity seems to be fluctuating
I agree. I did that when I first put it in, but it works just fine when I take it out. Changing the acceleration on that axis fixed the problem. Really appreciate the help!!