Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/Movement/Kinematics/PolarKinematics.cpp')
-rw-r--r--src/Movement/Kinematics/PolarKinematics.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/src/Movement/Kinematics/PolarKinematics.cpp b/src/Movement/Kinematics/PolarKinematics.cpp
new file mode 100644
index 00000000..8d1eb8b8
--- /dev/null
+++ b/src/Movement/Kinematics/PolarKinematics.cpp
@@ -0,0 +1,260 @@
+/*
+ * PolarKinematics.cpp
+ *
+ * Created on: 13 Oct 2017
+ * Author: David
+ */
+
+#include "PolarKinematics.h"
+
+#include "RepRap.h"
+#include "Platform.h"
+#include "Storage/MassStorage.h"
+#include "GCodes/GCodeBuffer.h"
+#include "Movement/DDA.h"
+
+// Constructor
+PolarKinematics::PolarKinematics()
+ : Kinematics(KinematicsType::polar, DefaultSegmentsPerSecond, DefaultMinSegmentSize, true),
+ minRadius(0.0), maxRadius(DefaultMaxRadius), homedRadius(0.0),
+ maxTurntableSpeed(DefaultMaxTurntableSpeed), maxTurntableAcceleration(DefaultMaxTurntableAcceleration)
+{
+ Recalc();
+}
+
+// Return the name of the current kinematics.
+// If 'forStatusReport' is true then the string must be the one for that kinematics expected by DuetWebControl and PanelDue.
+// Otherwise it should be in a format suitable for printing.
+// For any new kinematics, the same string can be returned regardless of the parameter.
+const char *PolarKinematics::GetName(bool forStatusReport) const
+{
+ return "Polar";
+}
+
+// Set or report the parameters from a M665, M666 or M669 command
+// If 'mCode' is an M-code used to set parameters for the current kinematics (which should only ever be 665, 666, 667 or 669)
+// then search for parameters used to configure the current kinematics. If any are found, perform appropriate actions,
+// and return true if the changes affect the geometry.
+// If errors were discovered while processing parameters, put an appropriate error message in 'reply' and set 'error' to true.
+// If no relevant parameters are found, print the existing ones to 'reply' and return false.
+// If 'mCode' does not apply to this kinematics, call the base class version of this function, which will print a suitable error message.
+bool PolarKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, StringRef& reply, bool& error)
+{
+ if (mCode == 669)
+ {
+ bool seenNonGeometry = false;
+ gb.TryGetFValue('S', segmentsPerSecond, seenNonGeometry);
+ gb.TryGetFValue('T', minSegmentLength, seenNonGeometry);
+
+ bool seen = false;
+ if (gb.Seen('R'))
+ {
+ seen = true;
+ float radiusLimits[2];
+ size_t numRadiusLimits = 2;
+ gb.GetFloatArray(radiusLimits, numRadiusLimits, false);
+ if (numRadiusLimits == 2)
+ {
+ minRadius = radiusLimits[0];
+ maxRadius = radiusLimits[1];
+ }
+ else
+ {
+ minRadius = 0.0;
+ maxRadius = radiusLimits[0];
+ }
+ homedRadius = minRadius; // set up default
+ }
+
+ gb.TryGetFValue('H', homedRadius, seen);
+ gb.TryGetFValue('A', maxTurntableAcceleration, seenNonGeometry);
+ gb.TryGetFValue('F', maxTurntableSpeed, seenNonGeometry);
+
+ if (seen || seenNonGeometry)
+ {
+ Recalc();
+ }
+ else
+ {
+ reply.printf("Printer mode is Polar with radius %.1f to %.1fmm, homed radius %.1fmm, segments/sec %d, min. segment length %.2f",
+ (double)minRadius, (double)maxRadius, (double)homedRadius,
+ (int)segmentsPerSecond, (double)minSegmentLength);
+ }
+ return seen;
+ }
+ else
+ {
+ return Kinematics::Configure(mCode, gb, reply, error);
+ }
+}
+
+// Convert Cartesian coordinates to motor positions measured in steps from reference position
+// 'machinePos' is a set of axis and extruder positions to convert
+// 'stepsPerMm' is as configured in M92. On a Scara or polar machine this would actually be steps per degree.
+// 'numAxes' is the number of machine axes to convert, which will always be at least 3
+// 'motorPos' is the output vector of motor positions
+// Return true if successful, false if we were unable to convert
+bool PolarKinematics::CartesianToMotorSteps(const float machinePos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, int32_t motorPos[], bool isCoordinated) const
+{
+ motorPos[0] = lrintf(sqrtf(fsquare(machinePos[0]) + fsquare(machinePos[1])) * stepsPerMm[0]);
+ motorPos[1] = (motorPos[0] == 0.0) ? 0 : lrintf(atan2f(machinePos[1], machinePos[0]) * RadiansToDegrees * stepsPerMm[1]);
+
+ // Transform remaining axes linearly
+ for (size_t axis = Z_AXIS; axis < numVisibleAxes; ++axis)
+ {
+ motorPos[axis] = lrintf(machinePos[axis] * stepsPerMm[axis]);
+ }
+ return true;
+}
+
+// Convert motor positions (measured in steps from reference position) to Cartesian coordinates
+// 'motorPos' is the input vector of motor positions
+// 'stepsPerMm' is as configured in M92. On a Scara or polar machine this would actually be steps per degree.
+// 'numDrives' is the number of machine drives to convert, which will always be at least 3
+// 'machinePos' is the output set of converted axis and extruder positions
+void PolarKinematics::MotorStepsToCartesian(const int32_t motorPos[], const float stepsPerMm[], size_t numVisibleAxes, size_t numTotalAxes, float machinePos[]) const
+{
+ const float angle = (motorPos[1] * DegreesToRadians)/stepsPerMm[1];
+ const float radius = (float)motorPos[0]/stepsPerMm[0];
+ machinePos[0] = radius * cosf(angle);
+ machinePos[1] = radius * sinf(angle);
+
+ // Convert any additional axes linearly
+ for (size_t drive = Z_AXIS; drive < numVisibleAxes; ++drive)
+ {
+ machinePos[drive] = motorPos[drive]/stepsPerMm[drive];
+ }
+}
+
+// Return true if the specified XY position is reachable by the print head reference point.
+bool PolarKinematics::IsReachable(float x, float y, bool isCoordinated) const
+{
+ const float r2 = fsquare(x) + fsquare(y);
+ return r2 >= minRadiusSquared && r2 <= maxRadiusSquared;
+}
+
+// Limit the Cartesian position that the user wants to move to, returning true if any coordinates were changed
+bool PolarKinematics::LimitPosition(float position[], size_t numAxes, AxesBitmap axesHomed, bool isCoordinated) const
+{
+ const bool m208Limited = Kinematics::LimitPositionFromAxis(position, Z_AXIS, numAxes, axesHomed); // call base class function to limit Z and higher axes
+ const float r2 = fsquare(position[0]) + fsquare(position[1]);
+ bool radiusLimited;
+ if (r2 < minRadiusSquared)
+ {
+ radiusLimited = true;
+ const float r = sqrtf(r2);
+ if (r < 0.01)
+ {
+ position[0] = minRadius;
+ position[1] = 0.0;
+ }
+ else
+ {
+ position[0] *= minRadius/r;
+ position[1] *= minRadius/r;
+ }
+ }
+ else if (r2 > maxRadiusSquared)
+ {
+ radiusLimited = true;
+ const float r = sqrtf(r2);
+ position[0] *= maxRadius/r;
+ position[1] *= maxRadius/r;
+ }
+ else
+ {
+ radiusLimited = false;
+ }
+
+ return m208Limited || radiusLimited;
+}
+
+// Return the initial Cartesian coordinates we assume after switching to this kinematics
+void PolarKinematics::GetAssumedInitialPosition(size_t numAxes, float positions[]) const
+{
+ for (size_t i = 0; i < numAxes; ++i)
+ {
+ positions[i] = 0.0;
+ }
+}
+
+// Return the axes that we can assume are homed after executing a G92 command to set the specified axis coordinates
+AxesBitmap PolarKinematics::AxesAssumedHomed(AxesBitmap g92Axes) const
+{
+ // If both X and Y have been specified then we know the positions the radius motor and the turntable, otherwise we don't
+ const AxesBitmap xyAxes = MakeBitmap<AxesBitmap>(X_AXIS) | MakeBitmap<AxesBitmap>(Y_AXIS);
+ if ((g92Axes & xyAxes) != xyAxes)
+ {
+ g92Axes &= ~xyAxes;
+ }
+ return g92Axes;
+}
+
+// This function is called when a request is made to home the axes in 'toBeHomed' and the axes in 'alreadyHomed' have already been homed.
+// If we can proceed with homing some axes, return the name of the homing file to be called. Optionally, update 'alreadyHomed' to indicate
+// that some additional axes should be considered not homed.
+// If we can't proceed because other axes need to be homed first, return nullptr and pass those axes back in 'mustBeHomedFirst'.
+const char* PolarKinematics::GetHomingFileName(AxesBitmap toBeHomed, AxesBitmap alreadyHomed, size_t numVisibleAxes, AxesBitmap& mustHomeFirst) const
+{
+ // Ask the base class which homing file we should call first
+ const char* ret = Kinematics::GetHomingFileName(toBeHomed, alreadyHomed, numVisibleAxes, mustHomeFirst);
+ // Change the returned name if it is X or Y
+ if (ret == StandardHomingFileNames[X_AXIS])
+ {
+ ret = HomeRadiusFileName;
+ }
+ else if (ret == StandardHomingFileNames[Y_AXIS])
+ {
+ ret = HomeBedFileName;
+ }
+ return ret;
+}
+
+// This function is called from the step ISR when an endstop switch is triggered during homing.
+// Return true if the entire homing move should be terminated, false if only the motor associated with the endstop switch should be stopped.
+bool PolarKinematics::QueryTerminateHomingMove(size_t axis) const
+{
+ return false;
+}
+
+// This function is called from the step ISR when an endstop switch is triggered during homing after stopping just one motor or all motors.
+// Take the action needed to define the current position, normally by calling dda.SetDriveCoordinate() and return false.
+void PolarKinematics::OnHomingSwitchTriggered(size_t axis, bool highEnd, const float stepsPerMm[], DDA& dda) const
+{
+ switch(axis)
+ {
+ case X_AXIS: // radius
+ dda.SetDriveCoordinate(lrintf(homedRadius * stepsPerMm[axis]), axis);
+ break;
+
+ case Y_AXIS: // bed
+ dda.SetDriveCoordinate(0, axis);
+ break;
+
+ default:
+ const float hitPoint = (highEnd) ? reprap.GetPlatform().AxisMaximum(axis) : reprap.GetPlatform().AxisMinimum(axis);
+ dda.SetDriveCoordinate(lrintf(hitPoint * stepsPerMm[axis]), axis);
+ break;
+ }
+}
+
+// Limit the speed and acceleration of a move to values that the mechanics can handle.
+// The speeds in Cartesian space have already been limited.
+void PolarKinematics::LimitSpeedAndAcceleration(DDA& dda, const float *normalisedDirectionVector) const
+{
+ const int32_t turntableMovement = labs(dda.DriveCoordinates()[1] - dda.GetPrevious()->DriveCoordinates()[1]);
+ if (turntableMovement != 0)
+ {
+ const float stepRatio = dda.GetTotalDistance() * reprap.GetPlatform().DriveStepsPerUnit(1)/turntableMovement;
+ dda.LimitSpeedAndAcceleration(stepRatio * maxTurntableSpeed, stepRatio * maxTurntableAcceleration);
+ }
+}
+
+// Update the derived parameters after the master parameters have been changed
+void PolarKinematics::Recalc()
+{
+ minRadiusSquared = (minRadius <= 0.0) ? 0.0 : fsquare(minRadius);
+ maxRadiusSquared = fsquare(maxRadius);
+}
+
+// End