166 lines
5.6 KiB
C
166 lines
5.6 KiB
C
/*******************************************************************************
|
|
* Copyright © 2018 TRINAMIC Motion Control GmbH & Co. KG
|
|
* (now owned by Analog Devices Inc.),
|
|
*
|
|
* Copyright © 2023 Analog Devices Inc. All Rights Reserved. This software is
|
|
* proprietary & confidential to Analog Devices, Inc. and its licensors.
|
|
*******************************************************************************/
|
|
|
|
/*
|
|
* This is a basic proof-of-concept implementation of a linear motion ramp
|
|
* generator. It is designed to run with 1 calculation / ms.
|
|
*
|
|
*
|
|
*/
|
|
#include "LinearRamp.h"
|
|
|
|
void tmc_linearRamp_init(TMC_LinearRamp *linearRamp)
|
|
{
|
|
linearRamp->maxVelocity = 0;
|
|
linearRamp->targetPosition = 0;
|
|
linearRamp->targetVelocity = 0;
|
|
linearRamp->rampVelocity = 0;
|
|
linearRamp->acceleration = 0;
|
|
linearRamp->encoderSteps = u16_MAX;
|
|
linearRamp->lastdVRest = 0;
|
|
linearRamp->lastdXRest = 0;
|
|
linearRamp->rampEnabled = false;
|
|
}
|
|
|
|
void tmc_linearRamp_computeRampVelocity(TMC_LinearRamp *linearRamp)
|
|
{
|
|
if (linearRamp->rampEnabled)
|
|
{
|
|
// update target velocity according actual set acceleration
|
|
// (scaling pre-factor of 1000 used for 1ms velocity ramp handling)
|
|
|
|
int32_t dV = linearRamp->acceleration;
|
|
|
|
// to ensure that small velocity changes at high set acceleration are also possible
|
|
int32_t maxDTV = abs(linearRamp->targetVelocity - linearRamp->rampVelocity);
|
|
if (maxDTV < (dV/1000))
|
|
dV = maxDTV*1000;
|
|
|
|
dV += linearRamp->lastdVRest;
|
|
linearRamp->lastdVRest = dV % 1000;
|
|
|
|
if (linearRamp->rampVelocity < linearRamp->targetVelocity)
|
|
{
|
|
// accelerate motor
|
|
linearRamp->rampVelocity += dV/1000; // divide with pre-factor
|
|
}
|
|
else if (linearRamp->rampVelocity > linearRamp->targetVelocity)
|
|
{
|
|
// decelerate motor
|
|
linearRamp->rampVelocity -= dV/1000; // divide with pre-factor
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// use target velocity directly
|
|
linearRamp->rampVelocity = linearRamp->targetVelocity;
|
|
}
|
|
|
|
// limit ramp velocity
|
|
linearRamp->rampVelocity = tmc_limitInt(linearRamp->rampVelocity, -linearRamp->maxVelocity, linearRamp->maxVelocity);
|
|
}
|
|
|
|
void tmc_linearRamp_computeRampPosition(TMC_LinearRamp *linearRamp)
|
|
{
|
|
if (linearRamp->rampEnabled)
|
|
{
|
|
// update target position according actual set acceleration and max velocity
|
|
// (scaling pre-factor of 1000 used for 1ms position ramp handling)
|
|
|
|
// limit position difference for further computations
|
|
int32_t targetPositionsDifference = linearRamp->targetPosition-linearRamp->rampPosition;
|
|
|
|
// limit the sqrti value in case of high position differences
|
|
int64_t sqrtiValue = tmc_limitS64(((int64_t)120 * (int64_t)linearRamp->acceleration * (int64_t)(abs(targetPositionsDifference))) / (int64_t)linearRamp->encoderSteps, 0, (int64_t)linearRamp->maxVelocity*(int64_t)linearRamp->maxVelocity);
|
|
|
|
// compute max allowed ramp velocity to ramp down to target
|
|
int32_t maxRampStop = tmc_sqrti(sqrtiValue);
|
|
|
|
// compute max allowed ramp velocity
|
|
int32_t maxRampTargetVelocity = 0;
|
|
if (targetPositionsDifference > 0)
|
|
{
|
|
maxRampTargetVelocity = tmc_limitInt(maxRampStop, 0, (int32_t)linearRamp->maxVelocity);
|
|
}
|
|
else if (targetPositionsDifference < 0)
|
|
{
|
|
maxRampTargetVelocity = tmc_limitInt(-maxRampStop, -(int32_t)linearRamp->maxVelocity, 0);
|
|
}
|
|
else
|
|
{
|
|
//maxRampTargetVelocity = 0;
|
|
}
|
|
|
|
int32_t dV = linearRamp->acceleration; // pre-factor ~ 1/1000
|
|
|
|
// to ensure that small velocity changes at high set acceleration are also possible
|
|
int32_t maxDTV = abs(maxRampTargetVelocity - linearRamp->rampVelocity);
|
|
if (maxDTV < (dV / 1000))
|
|
dV = maxDTV * 1000;
|
|
|
|
dV += linearRamp->lastdVRest;
|
|
linearRamp->lastdVRest = dV % 1000;
|
|
|
|
// do velocity ramping
|
|
if (maxRampTargetVelocity > linearRamp->rampVelocity)
|
|
{
|
|
linearRamp->rampVelocity += dV / 1000;
|
|
}
|
|
else if (maxRampTargetVelocity < linearRamp->rampVelocity)
|
|
{
|
|
linearRamp->rampVelocity -= dV / 1000;
|
|
}
|
|
|
|
// limit positionRampTargetVelocity to maxRampTargetVelocity
|
|
//linearRamp->rampVelocity = tmc_limitInt(linearRamp->rampVelocity, -abs(maxRampTargetVelocity), abs(maxRampTargetVelocity));
|
|
|
|
// do position ramping using actual ramp velocity to update dX
|
|
int64_t dX = ((int64_t)linearRamp->rampVelocity * (int64_t)linearRamp->encoderSteps) / ((int64_t)60) + linearRamp->lastdXRest;
|
|
|
|
// scale actual target position
|
|
int64_t tempActualTargetPosition = (int64_t)linearRamp->rampPosition * 1000;
|
|
|
|
// reset helper variables if ramp position reached target position
|
|
if (abs(linearRamp->targetPosition - linearRamp->rampPosition) <= 10) /*abs(dX)*/
|
|
{
|
|
// sync ramp position with target position on small deviations
|
|
linearRamp->rampPosition = linearRamp->targetPosition;
|
|
|
|
// update actual target position
|
|
tempActualTargetPosition = (int64_t)linearRamp->rampPosition * 1000;
|
|
|
|
dX = 0;
|
|
linearRamp->lastdXRest = 0;
|
|
linearRamp->rampVelocity = 0;
|
|
}
|
|
else
|
|
{
|
|
// update actual target position
|
|
tempActualTargetPosition += dX;
|
|
}
|
|
|
|
int64_t absTempActualTargetPosition = (tempActualTargetPosition >= 0) ? tempActualTargetPosition : -tempActualTargetPosition;
|
|
|
|
if (tempActualTargetPosition >= 0)
|
|
linearRamp->lastdXRest = (absTempActualTargetPosition % 1000);
|
|
else if (tempActualTargetPosition < 0)
|
|
linearRamp->lastdXRest = -(absTempActualTargetPosition % 1000);
|
|
|
|
// scale actual target position back
|
|
linearRamp->rampPosition = tempActualTargetPosition / 1000;
|
|
}
|
|
else
|
|
{
|
|
// use target position directly
|
|
linearRamp->rampPosition = linearRamp->targetPosition;
|
|
|
|
// hold ramp velocity in reset
|
|
linearRamp->rampVelocity = 0;
|
|
}
|
|
}
|