Marlin代码分析一些记录

读Marlin代码理解

1、工作原理

Marlin固件分前后台系统。前台系统即主程序,后台系统则是中断程序。在Marlin中用到了两个定时器中断:定时器0和定时器1。
主程序在前台的任务有:
1、 与上位机进行通信,获得G指令
2、 进行G指令解析,区分指令内容及指令参数,并将参数换算为整数
3、 G指令的分类执行
4、 温度管理、限位开关和LCD的控制
在G指令的分类执行中,Marlin固件用到了队列的概念,将每条G指令变成一个运动block,一个block包含的与该G指令下运动所需的所有参数(终点坐标、速度、加速度、挤出丝量等)。在前台系统中,程序只负责对G指令进行分析,并计算和生成一个block,并将block打入block缓冲池中。其他,则是与上位机进行交互。
定时器0主要负责对挤出头的温度进行控制。在主程序中设置好定时器0的定时时间,等待定时中断的产生,并在中断中进行温度检测控制。
定时器1主要负责对步进电机进行控制,是Marlin中运动控制部分的核心。在主程序中先设置好定时器1的初始定时时间,等待中断后,在中断执行block中的运动。首先从block缓冲池中取一个block,分析该block中的运动参数,设置运动方向,然后调控步进电机运动。定时器1的定时时间就是步进电机的运动速度,所以在控制步进电机的速度方面,可以通过时间计算来实现。每个中断执行一个block中的1步或几步,这个参数在系统初始化时进行相关设置。
1.将arduino驱动stm32的库文件至于目录
C:\Users\anycubic.platformio\packages\framework-arduinoststm32后,
2.Marlin再执行python文件generic_create_variant.py 将驱动文件编译到本工程目录下面:E:\work\ttt\Marlin-mini-20210630\buildroot\share\PlatformIO
3.通过fastio.h作为中间件,去调用ST的寄存器操作。
4.在HAL/STM32/HAL.hZ中进一步封装使用

2、主程序控制部分

主程序控制部分程序流程图如下图所示:主要实现的功能也就是获取G指令,解析指令,处理指令,相关温度和活动轴管理。​

主程序流程图
在Get_command函数中主要是一些字符串的处理,获得相应字符串及相关参数等等,在process_command函数中则是一个大的switch-case语句,用来处理相关指令集等。Mange_heater函数则是PID温度控制部分。

3、运动控制部分

定时器1主要负责对步进电机进行控制,是Marlin中运动控制部分的核心。在主程序中先设置好定时器1的初始定时时间,等待中断后,在中断执行block中的运动。首先从block缓冲池中取一个block,分析该block中的运动参数,设置运动方向,然后调控步进电机运动。定时器1的定时时间就是步进电机的运动速度,所以在控制步进电机的速度方面,可以通过时间计算来实现。每个中断执行一个block中的1步或几步,这个参数在系统初始化时进行相关设置。
​ 运动控制部分定时器1中断流程图如下:


bresenham算法
在运动控制部分中用到了Bresenham算法,具体原理及实现过程如下:

算法实现流程图:

​步进电机控制代码解析
1.电机控制移动函数的处理过程:
先调用motion.cpp 中的
prepare_line_to_destination()
里面再调用motion.cpp 中的
line_to_destination_cartesian()
里面再调用planner.cpp中的
bool Planner::buffer_line(const float &rx, const float &ry, const float &rz, const float &e, const feedRate_t &fr_mm_s, const uint8_t extruder, const float millimeters
#if ENABLED(SCARA_FEEDRATE_SCALING)
, const float &inv_duration
#endif
)
里面再调用planner.cpp中的
buffer_segment(machine, fr_mm_s, extruder, millimeters);
里面再调用stepper.cpp中的
stepper.wake_up();
之后触发中断ISR()执行运动脉冲的发送处理等.

#1.路径规划
1.重要函数
// Set the current position in steps
void Stepper::set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e)
{
planner.synchronize();
const bool was_enabled = suspend(); //关闭 定时器输出比较中断
_set_position(a, b, c, e); //计算位置值到规划器中
if (was_enabled) wake_up(); //开启 定时器输出比较中断
}

2.重要参数
// Positions of stepper motors, in step units
static xyze_long_t count_position; //步进电机的位置

// Current stepper motor directions (+1 or -1)
static xyze_int8_t count_direction; //步进电机的方向

///
///
#2.具体电机移动指令处理
1.从串口或者SD读取指令
例如: G1 X50 Y25.8 E22.4 F30

解析GCODE指令字母后面值转化成浮点数值函数: get_destination_from_command();
void GcodeSuite::get_destination_from_command()
xyze_bool_t seen = { false, false, false, false };

#if ENABLED(CANCEL_OBJECTS)
const bool &skip_move = cancelable.skipping;
#else
constexpr bool skip_move = false;
#endif

// Get new XYZ position, whether absolute or relative
LOOP_XYZ(i) {
if ( (seen[i] = parser.seenval(XYZ_CHAR(i))) ) {
//读取x,y,z需要移动的距离,单位(mm)
const float v = parser.value_axis_units((AxisEnum)i);
if (skip_move)
destination[i] = current_position[i];
else
destination[i] = axis_is_relative(AxisEnum(i)) ? current_position[i] + v : LOGICAL_TO_NATIVE(v, i);
}
else
destination[i] = current_position[i];
}

2.发E轴移动指令时会对destination.e的值进行更新,即为E轴需要移动的距离(单位:mm)
// Get new E position, whether absolute or relative
if ( (seen.e = parser.seenval(‘E’)) ) {
const float v = parser.value_axis_units(E_AXIS);
destination.e = axis_is_relative(E_AXIS) ? current_position.e + v : v;
SERIAL_ECHOLNPAIR(“seen:”, destination.e);
}
else
{
destination.e = current_position.e;
SERIAL_ECHOLNPAIR(“no seen:”, destination.e);
}
3.对移动速度进行更新
if (parser.linearval(‘F’) > 0)
feedrate_mm_s = parser.value_feedrate();

4.步进电机驱动相关设置
1.获取电流
float getAxisCurrent_mA(const axis_t axis) //获取XYZ轴电机电流

float getAxisCurrent_mA(const extruder_t extruder)//获取E轴电机电流
2.电机驱动初始化
void Stepper::init()

5.限位开关状态设置
1.函数设置为false则限位开关失效,设置为true则限位开关使能生效
void setSoftEndstopState(const bool value)
2.限位开关状态读取
bool getSoftEndstopState()

3.限位开关中断设置(目前未使用)
attachInterrupt(digitalPinToInterrupt(PA6), endstop_ISR, CHANGE)

4.限位开关初始化(目前正在使用的方式)
void Endstops::init()
5.限位开关状态读取(采用读取IO状态的形式)
void O2 Endstops::report_states() {
TERN
(BLTOUCH, bltouch._set_SW_mode());
SERIAL_ECHOLNPGM(STR_M119_REPORT);
#define ES_REPORT(S) print_es_state(READ(S##_PIN) != S##ENDSTOP_INVERTING, PSTR(STR##S))
#if HAS_X_MIN
ES_REPORT(X_MIN);
6.步进规划器报告状态并丢弃位置移动内容
void Planner::endstop_triggered(const AxisEnum axis)

7.电机复位
1.设置位置状态并更新位置
set_axis_is_at_home(axis);
2. 调用该函数同步位置
sync_plan_position()
2. sync_plan_position调用该函数设置位置
planner.set_position_mm(current_position);

///
///
8.其它
Marlin固件中对每个一个运动block块都会有一个速度算法控制,因为步进电机在启动进的速度不能太大,必须要有一个加速的过程,因此,在速度控制时,Marlin固件采用的是梯形曲线速度控制算法。关于其速度的实现,则是通过控制定时器1的中断频率来实现,中断频率越快,输出的频数信号越频繁,步进电机速度越快。
具体调用的函数如下:
Motion.cpp的函数do_blocking_move_to(const float rx, const float ry, const float rz) (作用:规划移动到指定XYZ位置并且设置当前位置)调用函数line_to_current_position()(作用:从上次移动的位置规划移动到当前位置 ,它其调用buffer_liner()处理运动动作。)

Plan.buffer_liner()函数说明如下:
先调用apply_leveling()函数加入自动调平的补偿;
再调用buffer_segment()函数以
*添加一个新的线性移动到缓冲区的轴单位。
*在调用此命令之前,应该先调用调平和运动学。

​ 在plan.buffer_line()最后被调用,此函数的功能在于计算block的进入速度和退出速度,这只是初始计算,planner.recalculate_trapezoids()是进入速度和退出速度的最终计算,它将所有block的梯形曲线连接起来。下面这个函数planner.recalculate()​(函数主要计算运动控制块block_t中的相关变量的值。以添加一个新的线性移动到缓冲区。)它最主要是计算加速阶段、匀速阶段以及减速阶段的位移,当达不到额定速度时,匀速阶段的位移为零。 recalculate()其函数体内容为:
{
reverse_pass();​
forward_pass();
recalculate_trapezoids()
}
在plan.buffer_line()中,调用完calculate_trapezoid_for_block ()后调用此函数,planner.recalculate()中包含了三个函数,reverse_pass()是从后往前依次检查并计算block的进入速度,forward_pass()是从前往后依次检查并计算block的进入速度。其实质是这两个函数分别负责处理不同block的情况而存在的;再加上plan.buffer_line()中对block的进入速度的计算,利用recalculate_trapezoids()可将所有块两两相连。

9.block_t结构体
typedef struct {
long steps_x, steps_y, steps_z, steps_e; 每个坐标轴所需走的步数
unsigned long step_event_count; 完成这个block所需走的步数,steps_x, steps_y, steps_z, steps_e的最大值
long accelerate_until; 梯形曲线中的加速距离,单位steps
long decelerate_after; 加速和匀速的距离,单位steps
long acceleration_rate; 加速率,用来计算加速度
unsigned char direction_bits; 这个block的方向位,“1”反向,“0”正向,每一个位代表一个轴的方向
unsigned char active_extruder; 所用到的有效的挤出头
float nominal_speed; 额定速度,即梯形曲线的匀速阶段的速度
float entry_speed; 进入速度,即从上一个block进入到这个block的速度
float max_entry_speed; 最大进入速度,进入速度不能超过这个值
float millimeters; 总路程,单位mm
float acceleration;加速度,单位mm/sec^2
unsigned char recalculate_flag; 连接处重新计算梯形速度曲线的标志
unsigned char nominal_length_flag; 能达到额定速度的标志

// Settings for the trapezoid generator梯形速度曲线产生器的设置参数
unsigned long nominal_rate; 这个block的单位为steps/sec的额定速度
unsigned long initial_rate; 梯形曲线的初始速度/进入速度,单位steps/sec
unsigned long final_rate; 梯形曲线的退出速度,单位steps/sec
unsigned long acceleration_st; 单位为steps/sec^2的加速度
unsigned long fan_speed;风扇速度
volatile char busy;正在处理这个block的标志位,“1”表示正在执行这个block
} block_t;

10.控制电机移动函数
1.对应轴移动距离
setAxisPosition_mm(getAxisPosition_mm(X) - move_dis, X, 50);
setAxisPosition_mm(getAxisPosition_mm(Y) + move_dis, Y, 50);
setAxisPosition_mm(getAxisPosition_mm(Z) + move_dis, Z, 8);
2.
do_z_raise(_MAX(Z_CLEARANCE_BETWEEN_PROBES,Z_CLEARANCE_DEPLOY_PROBE));
void do_z_clearance(const float &zclear, const bool z_trusted/=true/, const bool raise_on_untrusted/=true/, const bool lower_allowed/=false/)
report_current_position(); //位置报告
11.电机驱动部分
1.电流设置
void TMCStepper::rms_current(uint16_t mA)
2.电机状态监控(开关设置)
#define MONITOR_DRIVER_STATUS

4.PID温度控制

   Marlin固件在进行初始化之后进入loop()循环,和运动控制部分一样,PID温度控制也可看为前后台系统,后台接收上位机传过来的G代码,通常为M190(设置打印床温度并通过while循环等待打印床达到目标温度)、M104(设置挤出头目标温度但不等待)和M109(设置挤出头温度并通过while循环等待挤出头达到目标温度)。loop()调用process_commands()针对解析过来的G代码执行设置目标温度并且调用manage_heater()计算出一个输出值。而挤出头和打印床的加热和保持温度恒定的任务则需要前台的ISR(TIME0)中断服务程序根据manage_heater()计算出的输出值来完成。
   在Marlin固件中,PID算法的采样周期T= ((16.0 * 8.0)/(F_CPU / 64.0 / 256.0)),而TIME0在比较定时中断模式下的中断时间t=128Clocks/ F_CPU,可算出T/t=16384。即在一个采样周期内,TIMEO共产生16384此中断,ISR(TIME0)通过连续不断的产生中断来控制加热开关并维持系统温度的稳定性和正确性。
  固件中,只有挤出头的加热采用了PID算法进行精确控制,而打印床只是运用了继电器开关来控制温度,当前温度<</span>目标温度±偏差温度(2℃),则继电器开进行加热,否则,继电器关进行冷却。​

PID温度控制整体流程图
结合Marlin固件中有效的G代码和由打印机使用的切片软件产生的G代码文件来看,PID温度控制只用到了M104、M190和M109。而M104只负责设置挤出头的目标温度,M190和M109才是真正分别对打印床和挤出头加热达到目标温度的G代码。从process_commands()开始进入PID温度控制模块,由状态机转入到M190和M109的功能部分,由一个while循环利用当前温度和目标问的条件来等待挤出头和打印床上升到目标温度直至稳定。
系统的加热过程类似于PWM波形,后台manage_heater()计算出的输出值相当于PWM的占空比,输出值越大,加热开关打开的时间越长;输出值越小,加热开关打开的时间越短;输出值为零,则关掉加热开关。综合来看,可称其为软件实现的PWM。
总体来看,PID温度控制部分主要可分为manage_heater()和ISR(TIME0)这两部分,manage_heater()体现出PID算法,负责计算输出值;ISR(TIME0)根据输出值负责控制加热开关和维持系统温度,体现出PWM的特性;而PID_autotune()只是温度控制部分的一个小的功能函数,用来调整P、I、D三个参数值,需要调用M303来执行,而在实例切片中产生的G_code来看,并没有调用M303。

manage_heater()函数流程图
soft_pwm和soft_pwm_bed分别为挤出头和打印床的温度控制输出值,二者的加热与否需要根据这两个值来判断。manage_heater()只负责计算输出值,挤出头的温度控制输出值由PID算法计算得出,而打印床的温度控制输出值只根据当前温度和目标温度的比较来设定,小于则输出值为128,大于则为0。加热的任务需要中断服务程序ISR(TIME0)根据这个输出值来控制加热开关。
ISR(TIME0)内部主要由测温和加热控制组成。测温部分采用状态机形式,每个时刻状态,程序做不同的事,具体可参见Marlin固件代码。​

4.风扇控制部分

1.自动加热到指定温度,风扇控制
void Temperature::checkExtruderAutoFans()

5.断料检测部分

1.原理
通过不断读取IO电平状态对计数值进行操作,运行中计数值不断减减,如果是非断料电平则填充满计数值,计数值小于0则认为是断料并暂停打印。
该部分使用函数主要如下:
FilamentRunout() //断料检测处理函数
event_filament_runout() //断料检测函数()
TERN_(HAS_FILAMENT_SENSOR, runout.run()); //断料检测任务
static inline void run() {
if ( enabled && !filament_ran_out
&& (printingIsActive() || TERN0(ADVANCED_PAUSE_FEATURE, did_pause_print))
) {
TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, cli()); // Prevent RunoutResponseDelayed::block_completed from accumulating here
response.run(); //不断减减消耗断料计数
sensor.run(); //通过poll_runout_states()函数对是否有料进行判断,有料则填充断料计数
const bool ran_out = response.has_run_out(); //断料计数小于0则确认断料
TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, sei());
if (ran_out) { //确认断料处理
filament_ran_out = true;
event_filament_runout();
planner.synchronize();
}
}
}
poll_runout_states() //通过调用poll_runout_pins()函数读断料检测引脚IO状态

2.相关配置
FILAMENT_RUNOUT_SENSOR 去掉注释,即可开启缺料检测功能。一般使用光电限位开关装在送丝机耗材入口处,高电平表示正常送丝,低电平表示缺料。
FIL_RUNOUT_INVERTING 设置为 true 可反转限位开关信号。
ENDSTOPPULLUP_FIL_RUNOUT 去掉注释,表示缺料检测引脚默认上拉,一般默认开启。
FILAMENT_RUNOUT_SCRIPT 设置缺料检测激活时运行的脚本,一般为 M600,使打印机暂时打印,换好耗材后,可继续打印。
//===========================================================================
//========================= Filament Runout Sensor ==========================
//===========================================================================
//#define FILAMENT_RUNOUT_SENSOR // Uncomment for defining a filament runout sensor such as a mechanical or opto endstop to check the existence of filament
// In RAMPS uses servo pin 2. Can be changed in pins file. For other boards pin definition should be made.
// It is assumed that when logic high = filament available
// when logic low = filament ran out
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
const bool FIL_RUNOUT_INVERTING = false; // set to true to invert the logic of the sensor.
#define ENDSTOPPULLUP_FIL_RUNOUT // Uncomment to use internal pullup for filament runout pins if the sensor is defined.
#define FILAMENT_RUNOUT_SCRIPT “M600”
#endif
针对Makeboard主板,可以打开 pins_RAMPS.h 文件,搜索 FIL_RUNOUT_PIN,看到如下代码:
1
2 // define digital pin 4 for the filament runout sensor. Use the RAMPS 1.4 digital input 4 on the servos connector
#define FIL_RUNOUT_PIN 4
将缺料检测引脚设置为任意空闲的限制开关,如 X_MAX_PIN,设置值为 2,将缺料检测光电限位开关插入 X-MAX 插座即可。

6.断电续打

1.断电前信息保存
在主循环loop函数的任务函数IDLE()里面,该位置负责断电续打处理。
在使能断电续打前提下,如果之前state为运行状态且引脚电平使能,则通过outage()不断读取电压值,连续偏移正常值3次,则调用_outage()保存断电前数据, 通过使用Load()函数 (可通过M504()再调用validate() ) 调用_load()再调用report() 再使用指令M413对信息进行保存.

#if ENABLED(POWER_LOSS_RECOVERY) && PIN_EXISTS(POWER_LOSS)
if (printJobOngoing()) recovery.outage();
#endif
M413()函数,断电信息保存函数,启用条件下,它通过调用save()把机器状态信息保存到info,再调用write()把info信息写入到SD卡对应存储地址中.
1.启用电源损耗恢复
M413 S1
2.禁用电源损耗恢复
M413 S0
3.报告断电恢复状态
M413
Power-loss recovery ON

2.重上电后恢复打印及其恢复或删除保存配置的相关函数
//加载保存在ERRPROM中的相关配置
SETUP_RUN(settings.first_load());

1.UI事件处理
void DgusTFT::ProcessPanelRequest()
其中检测到 恢复状态后 跳出恢复打印界面
if(AC_printer_resuming_from_power_outage == printer_state)
{
char filename[64] = { ‘\0’ };
ChangePageOfTFT(PAGE_OUTAGE_RECOVERY);
card.getLongPath(filename, recovery.info.sd_filename);
SendTxtToTFT(filename, TXT_OUTAGE_RECOVERY_FILE);
PlayTune(BEEPER_PIN, SOS, 1);
}
else
{
ChangePageOfTFT(PAGE_MAIN);
}
通过下面该函数切换状态
void DgusTFT::PowerLossRecovery() {
printer_state = AC_printer_resuming_from_power_outage; // Play tune to notify user we can recover.
}
通过下面函数进一步封装
void onPowerLossResume() { Dgus.PowerLossRecovery(); }
通过M1000来调用
void GcodeSuite::M1000()
通过check()来调用,确认是否需要恢复文件
void PrintJobRecovery::check()

2.主任务中的TERN_(SDSUPPORT, card.manage_media() (上电只进入一次); 调用manage_media()函数通过powerloss.cpp文件中的 PrintJobRecovery::check()调用load()从SD卡内存中读取断电前的信息恢复到info结构体中。

2.ui界面通过调用M1000指令从断电中恢复打印UI界面:
M1000() //更改printer_state状态为AC_printer_resuming_from_power_outa
跳转到 page3_handle() 中调用resumePrint();恢复打印。并通过ChangePageOfTFT(PAGE_STATUS2)进入打印界面;

3.删除恢复文件,清理恢复数据
void PrintJobRecovery::purge()

7.UI屏幕显示控制

Dgus_tft.cpp 处理相关UI界面与底层的交互,通过串口命令互相通讯。
重点关注函数:
void DgusTFT::IdleLoop() -> 屏幕内容刷新处理 及其接收到屏幕命令的处理函数

1.触摸屏处理函数
主循环idle()调用Ui_api.cpp中的update()中的onIdle()中的Dgus.IdleLoop()处理人机交互事件.
2.界面跳转函数:
ChangePageOfTFT(PAGE_FILE);
3.发送数据给屏显示函数:
char str_buf[20];
sprintf(str_buf, “%d”, feedrate_last);
SendTxtToTFT(str_buf, TXT_PRINT_SPEED);
4.显示页处理
static void page3_handle(void);
5.UI初始化显示
void DgusTFT::ParamInit()
6.主界面初始化显示页控制
void DgusTFT::ProcessPanelRequest()

7.lcd信息存储
void onStoreSettings(char *buff)
8.Lcd信息加载
void onLoadSettings(const char *buff)

8.自动调平

1.调平指令
//操作步骤如下:
G28 ;move X/Y Z to min endstops
; G29; 自动调平 不需要每次都设置,所以前面加了分号,注释掉了
; M500;保存 leveling data到EEPROM
M501;加载 EEPROM中的leveling data
M420 S1;启用床平整

调平相关指令
M420 S1 // 开启调平
M420 S0 // 关闭调平

/**************************
*程序中的函数执行
**************************/
1执行床调平校准后的脚本(指令G28)
process_subcommands_now_P(PSTR(Z_PROBE_END_SCRIPT));
2移动到指定XY位置获取Z轴的高度
/

  • -移动到给定的XY
  • -如果还没有部署探测器,请部署探测器
  • -探测床,找到Z位置
  • -取决于’stow’旗
  • -收起探测器,否则
  • -上升到中间高度
  • -返回被探测的Z位置
    /
    float Probe::probe_at_point(const float &rx, const float &ry, const ProbePtRaise raise_after/
    =PROBE_PT_NONE*/, const uint8_t verbose_level/=0/, const bool probe_relative/=true/, const bool sanity_check/=true/)

2.调用该函数,移动到具体位置xyz
void do_blocking_move_to(const xyz_pos_t &raw, const feedRate_t &fr_mm_s/=0.0f/)

#if 0
3.调平完成后双线性填充未探测的点
void extrapolate_unprobed_bed_level();
4.根据自动调平的结果是否更改当前坐标为补偿值的开关设置
void set_bed_leveling_enabled(const bool enable/=true/)
5.配置ENABLE_LEVELING_FADE_HEIGHT后,调平效果在指定位置衰减
#endif

6.获取当前XY位置对应Z探针的高度
float Probe::run_z_probe(const bool sanity_check/=true/)
9.其包含开始调平探针探测
try_to_probe() //获取前后两次的探针状态(或)
10.其再包含下放Z轴,获取z探针单次触发的状态
bool Probe::probe_down_to_z(const float z, const feedRate_t fr_mm_s);
12.其包含两次探针触发正常的状态下,Z轴高度的获取
// Do a first probe at the fast speed
if (try_to_probe(PSTR(“FAST”), z_probe_low_point, z_probe_fast_mm_s,
sanity_check, Z_CLEARANCE_BETWEEN_PROBES) )
return NAN;
const float first_probe_z = current_position.z;

13.设置自动调平探测几遍 2或者3
#define MULTIPLE_PROBING 2
14.探测脚状态读取函数
PROBE_TRIGGERED()

原理:
发送G29(自动调平命令)后的反应,打印机的Z-min会移动到四个不同XY坐标(固件中可以配置)进行探测。并且得到四个位置相对于G28确定的基准点的Z位置进行对比和计算,得到打印平台的倾斜程度,从而在以后的运动中,将各个位置的Z偏移补偿进去(同一层打印时,Z轴可能会动),从而完成自动调平功能。

1.UI界面通过调用injectCommands_P(PSTR(“G28\nG29”))函数先执行复位指令后执行自动调平指令使用abl文件夹下的G29.cpp中的G29()函数,随后更改为调平状态,并进入到调平界面中, 调平完后自动退出调平界面.
2.配置X方向和Y方向的探测点数(先执行完X方向探测,再执行Y方向探测)
#define GRID_MAX_POINTS_X 5
#define GRID_MAX_POINTS_Y GRID_MAX_POINTS_X
3.发送指令,开始调平
injectCommands_P(PSTR(“G28\nG29”));
printer_state = AC_printer_probing;
ChangePageOfTFT(PAGE_LEVELING);
4.调平配置选项
//#define AUTO_BED_LEVELING_3POINT
//#define AUTO_BED_LEVELING_LINEAR
//#define AUTO_BED_LEVELING_BILINEAR
//#define AUTO_BED_LEVELING_UBL
//#define MESH_BED_LEVELING
只需要选择一种调平方式:
AUTO_BED_LEVELING_3POINT,三点调平,探测三角形中的三个点。平面给出适合于补偿平坦但倾斜的床的变换矩阵。
AUTO_BED_LEVELING_LINEAR,网格调平,探测网格中的床。通过最小二乘法生成变换矩阵,以补偿平坦但倾斜的床。
AUTO_BED_LEVELING_BILINEAR,通过可选的 Catmull-Rom 曲面细分在网格中探测床。网格数据用于使用双线性插值来调整整个床层的Z高度。适用于三角床,大床或不平坦的床。
AUTO_BED_LEVELING_UBL (推荐),结合了3点,线性,双线性和网格水准测量的功能。与双线性调平一样,UBL生成的网格数据用于使用双线性插值来调整整个床层的 Z 高度。当前需要 LCD 控制器。
MESH_BED_LEVELING提供了一个自定义G29命令,可使用一张纸或塞尺在几个网格点上测量床高。有关完整过程,请参阅G29。这种类型的调平仅与PROBE_MANUALLY兼容。
只有AUTO_BED_LEVELING_BILINEAR和AUTO_BED_LEVELING_UBL支持 Delta。当前仅AUTO_BED_LEVELING_BILINEAR支持 SCARA。MESH_BED_LEVELING与 Delta 和 SCARA 不兼容。

//======= Bed Auto Leveling ===========================
//是否开启自动调功能,如果开启,删除前面的//
//#define ENABLE_AUTO_BED_LEVELING // Delete the comment to enable (remove // at the start of the line)
//下面开始是针对自动调
功能的具体设置
#ifdef ENABLE_AUTO_BED_LEVELING
// these are the positions on the bed to do the probing
//自动调时的4个位置,为了防止测试时挤出机超出XY轴的范围,可以适当调整下面参数,让这几个参数都靠打印台中心位置的坐标

  • 6
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路过的小熊~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值