/******************************************************************************* * 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. *******************************************************************************/ #include "LinearRamp1.h" #include "tmc/helpers/Functions.h" void tmc_ramp_linear_init(TMC_LinearRamp *linearRamp) { linearRamp->maxVelocity = 0; linearRamp->targetPosition = 0; linearRamp->targetVelocity = 0; linearRamp->rampVelocity = 0; linearRamp->rampPosition = 0; linearRamp->acceleration = 0; linearRamp->rampEnabled = true; linearRamp->accumulatorVelocity = 0; linearRamp->accumulatorPosition = 0; linearRamp->rampMode = TMC_RAMP_LINEAR_MODE_VELOCITY; linearRamp->state = TMC_RAMP_LINEAR_STATE_IDLE; linearRamp->precision = TMC_RAMP_LINEAR_DEFAULT_PRECISION; linearRamp->homingDistance = TMC_RAMP_LINEAR_DEFAULT_HOMING_DISTANCE; linearRamp->stopVelocity = TMC_RAMP_LINEAR_DEFAULT_STOP_VELOCITY; } void tmc_ramp_linear_set_enabled(TMC_LinearRamp *linearRamp, bool enabled) { linearRamp->rampEnabled = enabled; } void tmc_ramp_linear_set_maxVelocity(TMC_LinearRamp *linearRamp, uint32_t maxVelocity) { linearRamp->maxVelocity = maxVelocity; } void tmc_ramp_linear_set_targetPosition(TMC_LinearRamp *linearRamp, int32_t targetPosition) { linearRamp->targetPosition = targetPosition; } void tmc_ramp_linear_set_rampPosition(TMC_LinearRamp *linearRamp, int32_t rampPosition) { linearRamp->rampPosition = rampPosition; } void tmc_ramp_linear_set_targetVelocity(TMC_LinearRamp *linearRamp, int32_t targetVelocity) { linearRamp->targetVelocity = targetVelocity; } void tmc_ramp_linear_set_rampVelocity(TMC_LinearRamp *linearRamp, int32_t rampVelocity) { linearRamp->rampVelocity = rampVelocity; } void tmc_ramp_linear_set_acceleration(TMC_LinearRamp *linearRamp, int32_t acceleration) { linearRamp->acceleration = acceleration; } void tmc_ramp_linear_set_mode(TMC_LinearRamp *linearRamp, TMC_LinearRamp_Mode mode) { linearRamp->rampMode = mode; } void tmc_ramp_linear_set_precision(TMC_LinearRamp * linearRamp, uint32_t precision) { linearRamp->precision = precision; } void tmc_ramp_linear_set_homingDistance(TMC_LinearRamp *linearRamp, uint32_t homingDistance) { linearRamp->homingDistance = homingDistance; } void tmc_ramp_linear_set_stopVelocity(TMC_LinearRamp *linearRamp, uint32_t stopVelocity) { linearRamp->stopVelocity = stopVelocity; } bool tmc_ramp_linear_get_enabled(TMC_LinearRamp *linearRamp) { return linearRamp->rampEnabled; } uint32_t tmc_ramp_linear_get_maxVelocity(TMC_LinearRamp *linearRamp) { return linearRamp->maxVelocity; } int32_t tmc_ramp_linear_get_targetPosition(TMC_LinearRamp *linearRamp) { return linearRamp->targetPosition; } int32_t tmc_ramp_linear_get_rampPosition(TMC_LinearRamp *linearRamp) { return linearRamp->rampPosition; } int32_t tmc_ramp_linear_get_targetVelocity(TMC_LinearRamp *linearRamp) { return linearRamp->targetVelocity; } int32_t tmc_ramp_linear_get_rampVelocity(TMC_LinearRamp *linearRamp) { return linearRamp->rampVelocity; } int32_t tmc_ramp_linear_get_acceleration(TMC_LinearRamp *linearRamp) { return linearRamp->acceleration; } TMC_LinearRamp_State tmc_ramp_linear_get_state(TMC_LinearRamp *linearRamp) { return linearRamp->state; } TMC_LinearRamp_Mode tmc_ramp_linear_get_mode(TMC_LinearRamp *linearRamp) { return linearRamp->rampMode; } uint32_t tmc_ramp_linear_get_precision(TMC_LinearRamp *linearRamp) { return linearRamp->precision; } // The maximum acceleration depends on the precision value uint32_t tmc_ramp_linear_get_acceleration_limit(TMC_LinearRamp *linearRamp) { return (0xFFFFFFFFu / linearRamp->precision) * linearRamp->precision; } uint32_t tmc_ramp_linear_get_velocity_limit(TMC_LinearRamp *linearRamp) { return linearRamp->precision; } uint32_t tmc_ramp_linear_get_homingDistance(TMC_LinearRamp *linearRamp) { return linearRamp->homingDistance; } uint32_t tmc_ramp_linear_get_stopVelocity(TMC_LinearRamp *linearRamp) { return linearRamp->stopVelocity; } int32_t tmc_ramp_linear_compute(TMC_LinearRamp *linearRamp) { tmc_ramp_linear_compute_position(linearRamp); return tmc_ramp_linear_compute_velocity(linearRamp); } int32_t tmc_ramp_linear_compute_velocity(TMC_LinearRamp *linearRamp) { bool accelerating = linearRamp->rampVelocity != linearRamp->targetVelocity; if (linearRamp->rampEnabled) { // Add current acceleration to accumulator linearRamp->accumulatorVelocity += linearRamp->acceleration; // Calculate the velocity delta value and keep the remainder of the velocity accumulator int32_t dv = linearRamp->accumulatorVelocity / linearRamp->precision; linearRamp->accumulatorVelocity = linearRamp->accumulatorVelocity % linearRamp->precision; // Add dv to rampVelocity, and regulate to target velocity if(linearRamp->rampVelocity < linearRamp->targetVelocity) linearRamp->rampVelocity = MIN(linearRamp->rampVelocity + dv, linearRamp->targetVelocity); else if(linearRamp->rampVelocity > linearRamp->targetVelocity) linearRamp->rampVelocity = MAX(linearRamp->rampVelocity - dv, linearRamp->targetVelocity); } else { // use target velocity directly linearRamp->rampVelocity = linearRamp->targetVelocity; // Reset accumulator linearRamp->accumulatorVelocity = 0; } // Calculate the velocity delta value and keep the remainder of the position accumulator linearRamp->accumulatorPosition += linearRamp->rampVelocity; int32_t dx = linearRamp->accumulatorPosition / (int32_t) linearRamp->precision; linearRamp->accumulatorPosition = linearRamp->accumulatorPosition % (int32_t) linearRamp->precision; if(dx == 0) return dx; // Change actual position determined by position change linearRamp->rampPosition += (dx < 0) ? (-1) : (1); // Count acceleration steps needed for decelerating later linearRamp->accelerationSteps += (abs(linearRamp->rampVelocity) < abs(linearRamp->targetVelocity)) ? accelerating : -accelerating; if (linearRamp->accelerationSteps < 0) linearRamp->accelerationSteps = 0; return dx; } void tmc_ramp_linear_compute_position(TMC_LinearRamp *linearRamp) { if (!linearRamp->rampEnabled) return; if (linearRamp->rampMode != TMC_RAMP_LINEAR_MODE_POSITION) return; // Calculate steps needed to target int32_t diffx = 0; switch(linearRamp->state) { case TMC_RAMP_LINEAR_STATE_IDLE: if(linearRamp->rampVelocity == 0) linearRamp->accelerationSteps = 0; if(linearRamp->rampPosition == linearRamp->targetPosition) break; linearRamp->state = TMC_RAMP_LINEAR_STATE_DRIVING; break; case TMC_RAMP_LINEAR_STATE_DRIVING: // Calculate distance to target (positive = driving towards target) if(linearRamp->rampVelocity > 0) diffx = linearRamp->targetPosition - linearRamp->rampPosition; else if(linearRamp->rampVelocity < 0) diffx = -(linearRamp->targetPosition - linearRamp->rampPosition); else diffx = abs(linearRamp->targetPosition - linearRamp->rampPosition); // Steps left required for braking? // (+ 1 to compensate rounding (flooring) errors of the position accumulator) if(linearRamp->accelerationSteps + 1 >= diffx) { linearRamp->targetVelocity = 0; linearRamp->state = TMC_RAMP_LINEAR_STATE_BRAKING; } else { // Driving - apply VMAX (this also allows mid-ramp VMAX changes) linearRamp->targetVelocity = (linearRamp->targetPosition > linearRamp->rampPosition) ? linearRamp->maxVelocity : -linearRamp->maxVelocity; } break; case TMC_RAMP_LINEAR_STATE_BRAKING: if(linearRamp->targetPosition == linearRamp->rampPosition) { if(abs(linearRamp->rampVelocity) <= linearRamp->stopVelocity) { // Position reached, velocity within cutoff threshold (or zero) linearRamp->rampVelocity = 0; linearRamp->targetVelocity = 0; linearRamp->state = TMC_RAMP_LINEAR_STATE_IDLE; } else { // We're still too fast, we're going to miss the target position // Let the deceleration continue until velocity is zero, then either // home when within homing distance or start a new ramp (RAMP_DRIVING) // towards the target. } } else { // We're not at the target position if(linearRamp->rampVelocity != 0) { // Still decelerating // Calculate distance to target (positive = driving towards target) if(linearRamp->rampVelocity > 0) diffx = linearRamp->targetPosition - linearRamp->rampPosition; else if(linearRamp->rampVelocity < 0) diffx = -(linearRamp->targetPosition - linearRamp->rampPosition); else diffx = abs(linearRamp->targetPosition - linearRamp->rampPosition); // Enough space to accelerate again? // (+ 1 to compensate rounding (flooring) errors of the position accumulator) if(linearRamp->accelerationSteps + 1 < diffx) { linearRamp->state = TMC_RAMP_LINEAR_STATE_DRIVING; } } else { // Standing still (not at the target position) if(abs(linearRamp->targetPosition - linearRamp->rampPosition) <= linearRamp->homingDistance) { // Within homing distance - drive with stop velocity linearRamp->targetVelocity = (linearRamp->targetPosition > linearRamp->rampPosition)? linearRamp->stopVelocity : -linearRamp->stopVelocity; } else { // Not within homing distance - start a new motion by switching to RAMP_IDLE // Since (targetPosition != actualPosition) a new ramp will be started. linearRamp->state = TMC_RAMP_LINEAR_STATE_IDLE; } } } break; } }