diff --git a/src/Movement/Kinematics/HangprinterKinematics.cpp b/src/Movement/Kinematics/HangprinterKinematics.cpp index 4c692ad347..af21b1bf49 100644 --- a/src/Movement/Kinematics/HangprinterKinematics.cpp +++ b/src/Movement/Kinematics/HangprinterKinematics.cpp @@ -99,6 +99,7 @@ void HangprinterKinematics::Init() noexcept constexpr float DefaultTorqueConstants[HANGPRINTER_AXES] = { 0.0F }; ARRAY_INIT(anchors, DefaultAnchors); + anchorMode = HangprinterAnchorMode::LastOnTop; printRadius = DefaultPrintRadius; spoolBuildupFactor = DefaultSpoolBuildupFactor; ARRAY_INIT(spoolRadii, DefaultSpoolRadii); @@ -229,6 +230,12 @@ bool HangprinterKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const } else if (mCode == 666) { + // 0=None, 1=last-top, 2=all-top, 3-half-top, etc + uint32_t unsignedAnchorMode = (uint32_t)anchorMode; + gb.TryGetUIValue('T', unsignedAnchorMode, seen); + if (unsignedAnchorMode <= (uint32_t)HangprinterAnchorMode::AllOnTop) { + anchorMode = (HangprinterAnchorMode)unsignedAnchorMode; + } gb.TryGetFValue('Q', spoolBuildupFactor, seen); gb.TryGetFloatArray('R', HANGPRINTER_AXES, spoolRadii, seen); gb.TryGetUIArray('U', HANGPRINTER_AXES, mechanicalAdvantage, seen); @@ -248,7 +255,8 @@ bool HangprinterKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const } else { - reply.printf("M666 Q%.4f\n", (double)spoolBuildupFactor); + // TODO T is taken, find a letter that's free + reply.printf("M666 T%u Q%.4f\n", (unsigned)anchorMode, (double)spoolBuildupFactor); reply.lcatf("R%.2f", (double)spoolRadii[0]); for (size_t i = 1; i < HANGPRINTER_AXES; ++i) @@ -444,25 +452,51 @@ static bool isSameSide(float const v0[3], float const v1[3], float const v2[3], return dot0*dot1 > 0.0F; } -// For each triangle side in a pseudo-pyramid, check if the point is inside the pyramid (Except for the base) -// Also check that any point below the line between two exterior anchors (all anchors are exterior except for the last one) -// is in the "inside part" all the way down to min_Z, however low it may be. -// To further limit the movements in the X and Y axes one can simply set a smaller print radius. -bool HangprinterKinematics::IsReachable(float axesCoords[MaxAxes], AxesBitmap axes) const noexcept /*override*/ +bool HangprinterKinematics::IsInsidePyramidSides(float const coords[3]) const noexcept { - float const coords[3] = {axesCoords[X_AXIS], axesCoords[Y_AXIS], axesCoords[Z_AXIS]}; bool reachable = true; // Check all the planes defined by triangle sides in the pyramid for (size_t i = 0; reachable && i < HANGPRINTER_AXES - 1; ++i) { reachable = reachable && isSameSide(anchors[i], anchors[(i+1) % (HANGPRINTER_AXES - 1)], anchors[HANGPRINTER_AXES - 1], anchors[(i+2) % (HANGPRINTER_AXES - 1)], coords); } + return reachable; +} + +bool HangprinterKinematics::IsInsidePrismSides(float const coords[3], unsigned const discount_last) const noexcept +{ + bool reachable = true; // For each side of the base, check the plane formed by side and another point bellow them in z. - for (size_t i = 0; reachable && i < HANGPRINTER_AXES - 1; ++i) { + for (size_t i = 0; reachable && i < HANGPRINTER_AXES - discount_last; ++i) { float const lower_point[3] = {anchors[i][0], anchors[i][1], anchors[i][2] - 1}; reachable = reachable && isSameSide(anchors[i], anchors[(i+1) % (HANGPRINTER_AXES - 1)], lower_point, anchors[(i+2) % (HANGPRINTER_AXES - 1)], coords); } + return reachable; +} + +// For each triangle side in a pseudo-pyramid, check if the point is inside the pyramid (Except for the base) +// Also check that any point below the line between two exterior anchors (all anchors are exterior except for the last one) +// is in the "inside part" all the way down to min_Z, however low it may be. +// To further limit the movements in the X and Y axes one can simply set a smaller print radius. +bool HangprinterKinematics::IsReachable(float axesCoords[MaxAxes], AxesBitmap axes) const noexcept /*override*/ +{ + float const coords[3] = {axesCoords[X_AXIS], axesCoords[Y_AXIS], axesCoords[Z_AXIS]}; + bool reachable = true; + + switch (anchorMode) { + case HangprinterAnchorMode::None: + return true; + + // This reaches a pyramid on top of the lower prism if the bed is below the lower anchors + case HangprinterAnchorMode::LastOnTop: + default: + reachable = IsInsidePyramidSides(coords); + return reachable && IsInsidePrismSides(coords, 1); + + case HangprinterAnchorMode::AllOnTop: + return IsInsidePrismSides(coords, 0); + }; return reachable; } @@ -586,7 +620,7 @@ bool HangprinterKinematics::WriteCalibrationParameters(FileStore *f) const noexc ok = f->Write(scratchString.c_str()); if (!ok) return false; - scratchString.printf("M666 Q%.6f ", (double)spoolBuildupFactor); + scratchString.printf("M666 T%u Q%.6f ", (unsigned)anchorMode, (double)spoolBuildupFactor); ok = f->Write(scratchString.c_str()); if (!ok) return false; diff --git a/src/Movement/Kinematics/HangprinterKinematics.h b/src/Movement/Kinematics/HangprinterKinematics.h index 34a9c7e87f..ea4fa8badb 100644 --- a/src/Movement/Kinematics/HangprinterKinematics.h +++ b/src/Movement/Kinematics/HangprinterKinematics.h @@ -12,6 +12,13 @@ #if SUPPORT_HANGPRINTER +// Different modes can be configured for different tradeoffs in terms of printing volumes and speeds +enum class HangprinterAnchorMode { + None, // All is reacheable in None anchor mode as printing volume + LastOnTop, // (Default) Rsults in a pyramid plus a prism below if the lower anchors are above the printing bed + AllOnTop, // Result in a prism (speeds get limited, specially going down in Z) +}; + class HangprinterKinematics : public RoundBedKinematics { public: @@ -55,6 +62,9 @@ class HangprinterKinematics : public RoundBedKinematics protected: DECLARE_OBJECT_MODEL_WITH_ARRAYS + bool IsInsidePyramidSides(float const coords[3]) const noexcept; + bool IsInsidePrismSides(float const coords[3], unsigned const discount_last) const noexcept; + private: // Basic facts about movement system const char* ANCHOR_CHARS = "ABCD"; @@ -72,6 +82,7 @@ class HangprinterKinematics : public RoundBedKinematics void PrintParameters(const StringRef& reply) const noexcept; // Print all the parameters for debugging // The real defaults are in the cpp file + HangprinterAnchorMode anchorMode = HangprinterAnchorMode::LastOnTop; float printRadius = 0.0F; float anchors[HANGPRINTER_AXES][3] = {{ 0.0, 0.0, 0.0}, { 0.0, 0.0, 0.0},