Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Marlin/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -2482,6 +2482,11 @@
//
//#define INCH_MODE_SUPPORT

//
// G93/G94 Feedrate mode support
//
//#define FEEDRATE_MODE_SUPPORT

//
// M149 Set temperature units support
//
Expand Down
1 change: 1 addition & 0 deletions Marlin/src/core/language.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
#define STR_ERR_MATERIAL_INDEX "M145 S<index> out of range (0-1)"
#define STR_ERR_M421_PARAMETERS "M421 incorrect parameter usage"
#define STR_ERR_BAD_PLANE_MODE "G5 requires XY plane mode"
#define STR_ERR_BAD_FEEDRATE_MODE "G5 currently requires units/min feedrate mode"
#define STR_ERR_MESH_XY "Mesh point out of range"
#define STR_ERR_ARC_ARGS "G2/G3 bad parameters"
#define STR_ERR_PROTECTED_PIN "Protected Pin"
Expand Down
8 changes: 6 additions & 2 deletions Marlin/src/gcode/bedlevel/G42.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ void GcodeSuite::G42() {
return;
}

TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true);

// Move to current_position, as modified by I, J, P parameters
destination = current_position;

Expand All @@ -68,15 +70,17 @@ void GcodeSuite::G42() {
}
#endif

const feedRate_t fval = parser.linearval('F'),
fr_mm_s = MMM_TO_MMS(fval > 0 ? fval : 0.0f);
const feedRate_t fval = parser.feedrateval('F'),
fr_mm_s = MMM_TO_MMS(fval);

// SCARA kinematic has "safe" XY raw moves
#if IS_SCARA
prepare_internal_fast_move_to_destination(fr_mm_s);
#else
prepare_internal_move_to_destination(fr_mm_s);
#endif

TERN_(FEEDRATE_MODE_SUPPORT, print_move = false);
}

#endif // HAS_MESH
6 changes: 3 additions & 3 deletions Marlin/src/gcode/feature/camera/M240.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,12 @@ void GcodeSuite::M240() {

#ifdef PHOTO_RETRACT_MM
const float rval = parser.linearval('R', _PHOTO_RETRACT_MM);
const feedRate_t sval = parser.feedrateval('S', TERN(ADVANCED_PAUSE_FEATURE, PAUSE_PARK_RETRACT_FEEDRATE, TERN(FWRETRACT, RETRACT_FEEDRATE, 45)));
const feedRate_t sval = MMM_TO_MMS(parser.feedrateval('S', TERN(ADVANCED_PAUSE_FEATURE, PAUSE_PARK_RETRACT_FEEDRATE, TERN(FWRETRACT, RETRACT_FEEDRATE, 45))));
e_move_m240(-rval, sval);
#endif

feedRate_t fr_mm_s = parser.feedrateval('F');
if (fr_mm_s) NOLESS(fr_mm_s, 10.0f);
feedRate_t fr_mm_s = MMM_TO_MMS(parser.feedrateval('F'));
if (fr_mm_s && TERN1(FEEDRATE_MODE_SUPPORT, parser.inverse_time_enabled)) NOLESS(fr_mm_s, 10.0f);

constexpr xyz_pos_t photo_position = PHOTO_POSITION;
xyz_pos_t raw = {
Expand Down
7 changes: 6 additions & 1 deletion Marlin/src/gcode/gcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ void GcodeSuite::get_destination_from_command() {
#endif

if (parser.floatval('F') > 0) {
const float fr_mm_min = parser.value_linear_units();
const float fr_mm_min = parser.value_feedrate();
feedrate_mm_s = MMM_TO_MMS(fr_mm_min);
// Update the cutter feed rate for use by M4 I set inline moves.
TERN_(LASER_FEATURE, cutter.feedrate_mm_m = fr_mm_min);
Expand Down Expand Up @@ -464,6 +464,11 @@ void GcodeSuite::process_parsed_command(bool no_ok/*=false*/) {

case 92: G92(); break; // G92: Set current axis position(s)

#if ENABLED(FEEDRATE_MODE_SUPPORT)
case 93: G93(); break; // G93: Set feedrate mode to inverse time
case 94: G94(); break; // G94: Set feedrate mode to length units per minute
#endif

#if ENABLED(CALIBRATION_GCODE)
case 425: G425(); break; // G425: Perform calibration with calibration cube
#endif
Expand Down
6 changes: 6 additions & 0 deletions Marlin/src/gcode/gcode.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,12 @@ class GcodeSuite {

static void G92();


#if ENABLED(FEEDRATE_MODE_SUPPORT)
static void G93();
static void G94();
#endif

#if ENABLED(CALIBRATION_GCODE)
static void G425();
#endif
Expand Down
12 changes: 12 additions & 0 deletions Marlin/src/gcode/motion/G0_G1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,21 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) {
#ifdef G0_FEEDRATE
feedRate_t old_feedrate;
#if ENABLED(VARIABLE_G0_FEEDRATE)
TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true);
if (fast_move) {
old_feedrate = feedrate_mm_s; // Back up the (old) motion mode feedrate
feedrate_mm_s = fast_move_feedrate; // Get G0 feedrate from last usage
}
#elif defined(FEEDRATE_MODE_SUPPORT)
if (fast_move) {
parser.print_move = false;
}
else {
parser.print_move = true;
}
#endif
#elif ENABLED(FEEDRATE_MODE_SUPPORT)
parser.print_move = true;
#endif

get_destination_from_command(); // Get X Y [Z[I[J[K]]]] [E] F (and set cutter power)
Expand Down Expand Up @@ -107,6 +117,8 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) {
if (fast_move) feedrate_mm_s = old_feedrate;
#endif

TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false);

#if ENABLED(NANODLP_Z_SYNC)
#if ENABLED(NANODLP_ALL_AXIS)
#define _MOVE_SYNC parser.seenval('X') || parser.seenval('Y') || parser.seenval('Z') // For any move wait and output sync message
Expand Down
19 changes: 16 additions & 3 deletions Marlin/src/gcode/motion/G2_G3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,17 @@ void plan_arc(
}

// Feedrate for the move, scaled by the feedrate multiplier
const feedRate_t scaled_fr_mm_s = MMS_SCALED(feedrate_mm_s);
#if ENABLED(FEEDRATE_MODE_SUPPORT)
const feedRate_t scaled_fr = MMS_SCALED(feedrate_mm_s);
const feedRate_t scaled_fr_mm_s = parser.inverse_time_enabled ? scaled_fr * flat_mm : scaled_fr;
#else
const feedRate_t scaled_fr_mm_s = MMS_SCALED(feedrate_mm_s);
#endif

// Get the ideal segment length for the move based on settings
const float ideal_segment_mm = (
#if ARC_SEGMENTS_PER_SEC // Length based on segments per second and feedrate
constrain(scaled_fr_mm_s * RECIPROCAL(ARC_SEGMENTS_PER_SEC), MIN_ARC_SEGMENT_MM, MAX_ARC_SEGMENT_MM)
constrain(scaled_fr_mm_s * RECIPROCAL(ARC_SEGMENTS_PER_SEC, MIN_ARC_SEGMENT_MM, MAX_ARC_SEGMENT_MM))
#else
MAX_ARC_SEGMENT_MM // Length using the maximum segment size
#endif
Expand All @@ -236,7 +241,11 @@ void plan_arc(
// Add hints to help optimize the move
PlannerHints hints;
#if ENABLED(FEEDRATE_SCALING)
hints.inv_duration = (scaled_fr_mm_s / flat_mm) * segments;
#if ENABLED(FEEDRATE_MODE_SUPPORT)
hints.inv_duration = segments * (parser.inverse_time_enabled ? scaled_fr : (scaled_fr_mm_s / flat_mm));
#else
hints.inv_duration = segments * (scaled_fr_mm_s / flat_mm);
#endif
#endif

/**
Expand Down Expand Up @@ -427,6 +436,8 @@ void GcodeSuite::G2_G3(const bool clockwise) {

TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_RUNNING));

TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true);

#if ENABLED(SF_ARC_FIX)
const bool relative_mode_backup = relative_mode;
relative_mode = true;
Expand Down Expand Up @@ -486,6 +497,8 @@ void GcodeSuite::G2_G3(const bool clockwise) {
else
SERIAL_ERROR_MSG(STR_ERR_ARC_ARGS);

TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false);

TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE));
}

Expand Down
7 changes: 7 additions & 0 deletions Marlin/src/gcode/motion/G5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ void GcodeSuite::G5() {
}
#endif

#if ENABLED(FEEDRATE_MODE_SUPPORT)
if (parser.inverse_time_enabled) {
SERIAL_ERROR_MSG(STR_ERR_BAD_FEEDRATE_MODE);
return;
}
#endif

get_destination_from_command();

const xy_pos_t offsets[2] = {
Expand Down
5 changes: 5 additions & 0 deletions Marlin/src/gcode/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ bool GCodeParser::volumetric_enabled;
float GCodeParser::linear_unit_factor, GCodeParser::volumetric_unit_factor;
#endif

#if ENABLED(FEEDRATE_MODE_SUPPORT)
bool GCodeParser::inverse_time_enabled;
bool GCodeParser::print_move;
#endif

#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
TempUnit GCodeParser::input_temp_units = TEMPUNIT_C;
#endif
Expand Down
13 changes: 12 additions & 1 deletion Marlin/src/gcode/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ class GCodeParser {
static float linear_unit_factor, volumetric_unit_factor;
#endif

#if ENABLED(FEEDRATE_MODE_SUPPORT)
static bool inverse_time_enabled;
static bool print_move;
#endif

#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
static TempUnit input_temp_units;
#endif
Expand Down Expand Up @@ -415,7 +420,13 @@ class GCodeParser {

#endif // !TEMPERATURE_UNITS_SUPPORT

static feedRate_t value_feedrate() { return MMM_TO_MMS(value_linear_units()); }
static feedRate_t value_feedrate() {
#if ENABLED(FEEDRATE_MODE_SUPPORT)
return (inverse_time_enabled && print_move) ? value_float() : value_linear_units();
#else
return value_linear_units();
#endif
}

void unknown_command_warning();

Expand Down
47 changes: 39 additions & 8 deletions Marlin/src/gcode/probe/G38.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,26 @@ inline void G38_single_probe(const uint8_t move_value) {
inline bool G38_run_probe() {

bool G38_pass_fail = false;
const xyze_pos_t start_pos = current_position;
const xyze_pos_t old_destination = destination;
probe.use_probing_tool();
if (probe.deploy()) {
SERIAL_ERROR_MSG("Failed to deploy probe");
endstops.not_homing();
probe.use_probing_tool(false);
return false;
}
const xyze_pos_t npos_start = start_pos - DIFF_TERN(HAS_HOTEND_OFFSET, probe.offset, hotend_offset[active_extruder]);
const xyze_pos_t npos_destination = old_destination - DIFF_TERN(HAS_HOTEND_OFFSET, probe.offset, hotend_offset[active_extruder]);
do_blocking_move_to(npos_start);
destination = npos_destination;


#if MULTIPLE_PROBING > 1
// Get direction of move and retract
xyz_float_t retract_mm;
LOOP_NUM_AXES(i) {
const float dist = destination[i] - current_position[i];
const float dist = npos_destination[i] - npos_start[i];
retract_mm[i] = ABS(dist) < G38_MINIMUM_MOVE ? 0 : home_bump_mm((AxisEnum)i) * (dist > 0 ? -1 : 1);
}
#endif
Expand Down Expand Up @@ -79,7 +93,15 @@ inline bool G38_run_probe() {
endstops.enable(false);
prepare_line_to_destination();
planner.synchronize();

#if ENABLED(SOLENOID_PROBE)
probe.stow();
safe_delay(1000);
if (probe.deploy()) {
endstops.not_homing();
probe.use_probing_tool(false);
return false;
}
#endif
REMEMBER(fr, feedrate_mm_s, feedrate_mm_s * 0.25);

// Bump the target more slowly
Expand All @@ -88,7 +110,13 @@ inline bool G38_run_probe() {
G38_single_probe(move_value);
#endif
}

endstops.enable(false);
TERN_(SOLENOID_PROBE, probe.stow());
const xyze_pos_t probed_pos = current_position + DIFF_TERN(HAS_HOTEND_OFFSET, probe.offset, hotend_offset[active_extruder]);
probe.use_probing_tool(false);
destination = probed_pos;
do_blocking_move_to(destination);
planner.synchronize();
endstops.not_homing();
return G38_pass_fail;
}
Expand All @@ -105,24 +133,27 @@ inline bool G38_run_probe() {
* G38.5 - Probe away from workpiece, stop on contact break
*/
void GcodeSuite::G38(const int8_t subcode) {

TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = true);
// Get X Y Z E F
get_destination_from_command();

remember_feedrate_scaling_off();

const bool error_on_fail = TERN(G38_PROBE_AWAY, !TEST(subcode, 0), subcode == 2);

// If any axis has enough movement, do the move
LOOP_NUM_AXES(i)
LOOP_NUM_AXES(i) {
if (ABS(destination[i] - current_position[i]) >= G38_MINIMUM_MOVE) {
if (!parser.seenval('F')) feedrate_mm_s = homing_feedrate((AxisEnum)i);
if (!parser.seenval('F')) {
TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false);
feedrate_mm_s = homing_feedrate((AxisEnum)i);
}
// If G38.2 fails throw an error
if (!G38_run_probe() && error_on_fail) SERIAL_ERROR_MSG("Failed to reach target");
break;
}

}
restore_feedrate_and_scaling();
TERN_(FEEDRATE_MODE_SUPPORT, parser.print_move = false);
}

#endif // G38_PROBE_TARGET
47 changes: 47 additions & 0 deletions Marlin/src/gcode/units/G93_G94.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2025 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

/**
* @file G93_G94.cpp
* @author DerAndere
* @brief G93 (inverse time mode) and G94 (units per minute feedrate mode).
*
* Copyright 2025 DerAndere
*/

#include "../../inc/MarlinConfig.h"

#if ENABLED(FEEDRATE_MODE_SUPPORT)

#include "../gcode.h"

/**
* G93: Set feedrate mode to inverse time
*/
void GcodeSuite::G93() { parser.inverse_time_enabled = true; }

/**
* G94: Set feedrate mode to length units per minute
*/
void GcodeSuite::G94() { parser.inverse_time_enabled = false; }

#endif // FEEDRATE_MODE_SUPPORT
1 change: 1 addition & 0 deletions Marlin/src/module/motion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ xyze_pos_t destination; // {0}
#define DEFAULT_FEEDRATE_MM_M 4000
#endif
feedRate_t feedrate_mm_s = MMM_TO_MMS(DEFAULT_FEEDRATE_MM_M);
//bool print_move = false;
int16_t feedrate_percentage = 100;
#if ENABLED(EDITABLE_HOMING_FEEDRATE)
xyz_feedrate_t homing_feedrate_mm_m = HOMING_FEEDRATE_MM_M;
Expand Down
2 changes: 2 additions & 0 deletions Marlin/src/module/motion.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ feedRate_t get_homing_bump_feedrate(const AxisEnum axis);
*/
extern feedRate_t feedrate_mm_s;

//extern bool print_move;

/**
* Feedrate scaling is applied to all G0/G1, G2/G3, and G5 moves
*/
Expand Down
Loading
Loading