From 6d30a0afb4e0b4ef615559d696be842e80ca5401 Mon Sep 17 00:00:00 2001 From: Reubertt Date: Sat, 24 Jan 2026 22:12:33 +0000 Subject: [PATCH 1/3] chore: remove trailing whitespace --- README.md | 28 +- .../Panda_segmentBed_I2C.cpp | 70 +- .../bdsensor_mega328p/Panda_segmentBed_I2C.h | 6 +- .../bdsensor_mega328p/bdsensor_mega328p.ino | 22 +- ardunio/esp32_vscode/README.md | 2 +- ardunio/esp32_vscode/platformio.ini | 2 +- ardunio/esp32_vscode/src/main.cpp | 16 +- klipper/BD_sensor.c | 44 +- klipper/BDsensor.py | 1124 ++++++++++------- klipper/install_BDsensor.sh | 2 +- klipper/uninstall.sh | 2 +- 11 files changed, 733 insertions(+), 585 deletions(-) diff --git a/README.md b/README.md index 68e0312a..54607091 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ it can measure the bed distance at any point in real time without moving the z a Faster leveling, realtime compensation, high accuracy. 1. No need to do probe points before every print, it will be automatically compensated for based on actual distance in real time. - + 2. You can do bed mesh leveling like a normal proximity sensor but much faster with this BDsensor. - + 3. Easy manual bed level adjustment thanks to ability to display the live sensor distance measurement on your screen. Sensor type: inductive, eddy, can only measure the metal plate. @@ -24,8 +24,8 @@ Range: 4mm (for different metal the range should be different, the normal pei st * Support high temperature chamber(120C) with the long cable probe [BDsensorM](https://github.com/markniu/Bed_Distance_sensor/wiki/BDsensor-M). ### Hardware Version . | hardware | firmware/software ---- | --- |--- -2022.6 | BDsensor VA, V1.0 | V1.0 +--- | --- |--- +2022.6 | BDsensor VA, V1.0 | V1.0 2023.4 | BDsensor VB, V1.1, the connector was changed | V1.1, support self reboot 2023.11 | BDsensor VB, V1.3, Upgrade the MCU to STM32 | V1.2, for stm32 2024.2 | |V1.2c, [Support nozzle collision sensing](https://github.com/markniu/Bed_Distance_sensor/wiki/Collision-sensing) @@ -35,15 +35,15 @@ Range: 4mm (for different metal the range should be different, the normal pei st ### Software . | Marlin | Klipper ---- | --- |--- -Real Time leveling |:heavy_check_mark:| :heavy_check_mark: -Fast bed mesh |:heavy_check_mark:| :heavy_check_mark: -Fast bed mesh(No toolhead stop)|:heavy_check_mark: | :heavy_check_mark: -Distance display |:heavy_check_mark: | :heavy_check_mark: -Can bus toolhead|No | :heavy_check_mark: -standby mode automatic while printing|:heavy_check_mark: | :heavy_check_mark: -[KAMP](https://github.com/kyleisah/Klipper-Adaptive-Meshing-Purging) Adaptive Meshing & Purging |No | :heavy_check_mark: -nozzle collision sensing|[Detail](https://github.com/markniu/Bed_Distance_sensor/wiki/Collision-sensing-for-Marlin):heavy_check_mark: | :heavy_check_mark: +--- | --- |--- +Real Time leveling |:heavy_check_mark:| :heavy_check_mark: +Fast bed mesh |:heavy_check_mark:| :heavy_check_mark: +Fast bed mesh(No toolhead stop)|:heavy_check_mark: | :heavy_check_mark: +Distance display |:heavy_check_mark: | :heavy_check_mark: +Can bus toolhead|No | :heavy_check_mark: +standby mode automatic while printing|:heavy_check_mark: | :heavy_check_mark: +[KAMP](https://github.com/kyleisah/Klipper-Adaptive-Meshing-Purging) Adaptive Meshing & Purging |No | :heavy_check_mark: +nozzle collision sensing|[Detail](https://github.com/markniu/Bed_Distance_sensor/wiki/Collision-sensing-for-Marlin):heavy_check_mark: | :heavy_check_mark: ### Benefit of Collision sensing 1. **Auto z offset calibration**. @@ -70,5 +70,5 @@ nozzle collision sensing|[Detail](https://github.com/markniu/Bed_Distance_sensor #### Where to buy: [pandapi3d.com](https://www.pandapi3d.com) , [elecrow](https://www.elecrow.com/bd-sensor.html) , [淘宝店](https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-14344044600.5.60a16ff77NRBL5&id=684572042388) - + diff --git a/ardunio/bdsensor_mega328p/Panda_segmentBed_I2C.cpp b/ardunio/bdsensor_mega328p/Panda_segmentBed_I2C.cpp index bd1684af..c0412125 100644 --- a/ardunio/bdsensor_mega328p/Panda_segmentBed_I2C.cpp +++ b/ardunio/bdsensor_mega328p/Panda_segmentBed_I2C.cpp @@ -9,9 +9,9 @@ int delay_time=100; void I2C_SegmentBED::setLow(unsigned char pin) { noInterrupts(); pinMode(pin, OUTPUT); - // if (_pullup) + // if (_pullup) digitalWrite(pin, LOW); - + interrupts(); } @@ -25,7 +25,7 @@ void I2C_SegmentBED::setHigh(unsigned char pin) { // digitalWrite(pin,1); // return; noInterrupts(); - //if (_pullup) + //if (_pullup) pinMode(pin, INPUT_PULLUP); // else // pinMode(pin, INPUT); @@ -50,7 +50,7 @@ int I2C_SegmentBED::i2c_init(unsigned char _sda,unsigned char _scl,unsigned cha } // Start transfer function: is the 8-bit I2C address (including the R/W -// bit). +// bit). // Return: true if the slave replies with an "acknowledge", false otherwise bool I2C_SegmentBED::i2c_start(unsigned char addr) { @@ -71,7 +71,7 @@ bool I2C_SegmentBED::i2c_start(unsigned char addr) { } */ // Repeated start function: After having claimed the bus with a start condition, -// you can address another or the same chip again without an intervening +// you can address another or the same chip again without an intervening // stop condition. // Return: true if the slave replies with an "acknowledge", false otherwise bool I2C_SegmentBED::i2c_rep_start(unsigned char addr) { @@ -97,7 +97,7 @@ void I2C_SegmentBED::i2c_stop(void) { // Return: true if the slave replies with an "acknowledge", false otherwise bool I2C_SegmentBED::i2c_write(unsigned char value) { for (unsigned char curr = 0X80; curr != 0; curr >>= 1) { - if (curr & value) {setHigh(I2C_BED_SDA);} else setLow(I2C_BED_SDA); + if (curr & value) {setHigh(I2C_BED_SDA);} else setLow(I2C_BED_SDA); setHigh(I2C_BED_SCL); delayMicroseconds(delay_time); setLow(I2C_BED_SCL); @@ -109,13 +109,13 @@ bool I2C_SegmentBED::i2c_write(unsigned char value) { delayMicroseconds(delay_time); unsigned char ack = digitalRead(I2C_BED_SDA); setLow(I2C_BED_SCL); - delayMicroseconds(delay_time); + delayMicroseconds(delay_time); setLow(I2C_BED_SDA); return ack == 0; } -// Read one byte. If is true, we send a NAK after having received -// the byte in order to terminate the read sequence. +// Read one byte. If is true, we send a NAK after having received +// the byte in order to terminate the read sequence. unsigned char I2C_SegmentBED::i2c_read(bool last) { unsigned char b = 0; setHigh(I2C_BED_SDA); @@ -131,7 +131,7 @@ unsigned char I2C_SegmentBED::i2c_read(bool last) { setHigh(I2C_BED_SCL); delayMicroseconds(delay_time); setLow(I2C_BED_SCL); - delayMicroseconds(delay_time); + delayMicroseconds(delay_time); setLow(I2C_BED_SDA); return b; } @@ -154,13 +154,13 @@ void I2C_SegmentBED::I2C_send_str(char *dat_r,char send_now) } i2c_stop(); } - - + + } void I2C_SegmentBED::I2C_read_str(char *dat_r,int addr) { - i2c_stop(); + i2c_stop(); if(i2c_start((I2C_7BITADDR<<1)|I2C_WRITE)) { int i =0; @@ -174,32 +174,32 @@ void I2C_SegmentBED::I2C_read_str(char *dat_r,int addr) i++; } i2c_read(true); - + } i2c_stop(); } //////////////////////////// - + unsigned short I2C_SegmentBED::BD_Add_OddEven(unsigned short byte) { unsigned char i; - unsigned char n; - unsigned short r; + unsigned char n; + unsigned short r; n =0; for(i=0;i<10;i++) { if(((byte >>i)&0x01) == 0x01) { n++; - } + } } if((n&0x01) == 0x01) { - r = byte | 0x400; + r = byte | 0x400; } else { - r = byte | 0x00; + r = byte | 0x00; } return r; } @@ -212,26 +212,26 @@ unsigned short I2C_SegmentBED::BD_Add_OddEven(unsigned short byte) unsigned short I2C_SegmentBED::BD_Check_OddEven(unsigned short byte) { unsigned char i; - unsigned char n; - unsigned char r; + unsigned char n; + unsigned char r; n =0; - for(i=0;i<10;i++) + for(i=0;i<10;i++) { if(((byte >>i)&0x01) == 0x01) { - n++; - } + n++; + } } - if((byte>>10) == (n&0x01)) + if((byte>>10) == (n&0x01)) { - r = BYTE_CHECK_OK; + r = BYTE_CHECK_OK; } else { - r = BYTE_CHECK_ERR; + r = BYTE_CHECK_ERR; } return r; -} +} void I2C_SegmentBED::BD_setLow(unsigned char pin) { noInterrupts(); @@ -279,7 +279,7 @@ void I2C_SegmentBED::BD_i2c_stop(void) { unsigned short I2C_SegmentBED::BD_i2c_read(void) { - + BD_I2C_start(); //// read BD_setHigh(I2C_BED_SDA); @@ -309,7 +309,7 @@ unsigned short I2C_SegmentBED::BD_i2c_read(void) void I2C_SegmentBED::BD_i2c_write(unsigned int addr) { - + BD_I2C_start(); //// write BD_setLow(I2C_BED_SDA); @@ -319,10 +319,10 @@ void I2C_SegmentBED::BD_i2c_write(unsigned int addr) addr=BD_Add_OddEven(addr); ///write address delayMicroseconds(delay_time); - for (int i=10; i >=0; i--) + for (int i=10; i >=0; i--) { - if ((addr>>i)&0x01) {BD_set_force_High(I2C_BED_SDA);} else BD_setLow(I2C_BED_SDA); - //if (addr &curr) {set_force_High(I2C_BED_SDA);} else setLow(I2C_BED_SDA); + if ((addr>>i)&0x01) {BD_set_force_High(I2C_BED_SDA);} else BD_setLow(I2C_BED_SDA); + //if (addr &curr) {set_force_High(I2C_BED_SDA);} else setLow(I2C_BED_SDA); BD_set_force_High(I2C_BED_SCL); delayMicroseconds(delay_time); BD_setLow(I2C_BED_SCL); @@ -330,6 +330,6 @@ void I2C_SegmentBED::BD_i2c_write(unsigned int addr) } //////////// BD_i2c_stop(); - + } diff --git a/ardunio/bdsensor_mega328p/Panda_segmentBed_I2C.h b/ardunio/bdsensor_mega328p/Panda_segmentBed_I2C.h index 16c43d41..f434982a 100644 --- a/ardunio/bdsensor_mega328p/Panda_segmentBed_I2C.h +++ b/ardunio/bdsensor_mega328p/Panda_segmentBed_I2C.h @@ -1,4 +1,4 @@ -// +// #ifndef Panda_segmentBed_I2C_h #define Panda_segmentBed_I2C_h @@ -9,13 +9,13 @@ #define I2C_MAXWAIT 5000 //#define I2C_7BITADDR 0x3C// DS1307 #define MEMLOC 0x0A -#define ADDRLEN 1 +#define ADDRLEN 1 class I2C_SegmentBED{ public: int i2c_init(unsigned char _sda,unsigned char _scl,unsigned char _addr,int delay_m); void I2C_read_str(char *dat_r,int addr); - void I2C_send_str(char *dat_r,char send_now); + void I2C_send_str(char *dat_r,char send_now); ////////////////////// void BD_i2c_write(unsigned int addr); unsigned short BD_i2c_read(void); diff --git a/ardunio/bdsensor_mega328p/bdsensor_mega328p.ino b/ardunio/bdsensor_mega328p/bdsensor_mega328p.ino index 86652563..2fcf9d2c 100644 --- a/ardunio/bdsensor_mega328p/bdsensor_mega328p.ino +++ b/ardunio/bdsensor_mega328p/bdsensor_mega328p.ino @@ -9,14 +9,14 @@ #endif I2C_SegmentBED BD_SENSOR_I2C; -#define I2C_BED_SDA 12 -#define I2C_BED_SCL 11 +#define I2C_BED_SDA 12 +#define I2C_BED_SCL 11 #define DELAY 100 #define MAX_BD_HEIGHT 6.9 #define CMD_START_READ_CALIBRATE_DATA 1017 #define CMD_END_READ_CALIBRATE_DATA 1018 #define CMD_START_CALIBRATE 1019 -#define CMD_END_CALIBRATE 1021 +#define CMD_END_CALIBRATE 1021 #define CMD_READ_VERSION 1016 #define CMD_DISTANCD_RAWDATA_TYPE 1020 // switch output distance data type to raw data, default is mm (1 represent 0.01mm) @@ -24,13 +24,13 @@ char tmp_1[50]; unsigned int n=0,i=0; float Distance=0.0; -U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); +U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); void dis_text(char *tmp_d,char x,char y) { - + u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font u8g2.drawStr(x,y,tmp_d); // write something to the internal memory u8g2.sendBuffer(); // transfer internal memory to the display @@ -40,7 +40,7 @@ void dis_text(char *tmp_d,char x,char y) unsigned short read_one_data() { unsigned short tmp=0; - tmp=BD_SENSOR_I2C.BD_i2c_read(); + tmp=BD_SENSOR_I2C.BD_i2c_read(); if(BD_SENSOR_I2C.BD_Check_OddEven(tmp)==0) //printf("CRC error!\n"); // sprintf(tmp_1,"CRC error"); @@ -83,21 +83,21 @@ void setup(void) { read_version(tmp_1+strlen(tmp_1)); dis_text(tmp_1,0,10); /// - + } void loop(void) { - u8g2.clearBuffer(); + u8g2.clearBuffer(); u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font //u8g2.drawStr(x,y,tmp_d); // write something to the internal memory - //u8g2.sendBuffer(); + //u8g2.sendBuffer(); sprintf(tmp_1,""); read_version(tmp_1+strlen(tmp_1)); //dis_text(tmp_1,0,10); u8g2.drawStr(0,10,tmp_1); - - //delay(10); + + //delay(10); //read and display raw data n=read_raw_data(); sprintf(tmp_1,"%d ",n); diff --git a/ardunio/esp32_vscode/README.md b/ardunio/esp32_vscode/README.md index e97a3029..5bf40c60 100644 --- a/ardunio/esp32_vscode/README.md +++ b/ardunio/esp32_vscode/README.md @@ -3,7 +3,7 @@ Arduino testing code This is a simple arduino testing code. It read the distance data from BDsensor after initial the communication port. -If you want to do more code by yourself for other application here is the protocol of data +If you want to do more code by yourself for other application here is the protocol of data https://github.com/markniu/Bed_Distance_sensor/wiki/Data-Protocol diff --git a/ardunio/esp32_vscode/platformio.ini b/ardunio/esp32_vscode/platformio.ini index 580c2345..fa660e50 100644 --- a/ardunio/esp32_vscode/platformio.ini +++ b/ardunio/esp32_vscode/platformio.ini @@ -12,7 +12,7 @@ platform = espressif32 board = esp32dev framework = arduino -lib_deps = +lib_deps = markyue/Panda_SoftMasterI2C diff --git a/ardunio/esp32_vscode/src/main.cpp b/ardunio/esp32_vscode/src/main.cpp index 6da3dd5e..f2c85a89 100644 --- a/ardunio/esp32_vscode/src/main.cpp +++ b/ardunio/esp32_vscode/src/main.cpp @@ -1,14 +1,14 @@ #include #include I2C_SegmentBED BD_SENSOR_I2C; -#define I2C_BED_SDA 2 -#define I2C_BED_SCL 15 +#define I2C_BED_SDA 2 +#define I2C_BED_SCL 15 #define DELAY 100 #define MAX_BD_HEIGHT 6.9 #define CMD_START_READ_CALIBRATE_DATA 1017 #define CMD_END_READ_CALIBRATE_DATA 1018 #define CMD_START_CALIBRATE 1019 -#define CMD_END_CALIBRATE 1021 +#define CMD_END_CALIBRATE 1021 #define CMD_READ_VERSION 1016 char tmp_1[50]; @@ -23,7 +23,7 @@ void setup() { void loop() { unsigned short tmp=0; - tmp=BD_SENSOR_I2C.BD_i2c_read(); + tmp=BD_SENSOR_I2C.BD_i2c_read(); if(BD_SENSOR_I2C.BD_Check_OddEven(tmp)==0) printf("CRC error!\n"); else @@ -33,7 +33,7 @@ void loop() { printf(tmp_1); } delay(100); - if((tmp&0x3ff)<1020) + if((tmp&0x3ff)<1020) { /////Read Calibrate data if(n==10) @@ -61,8 +61,8 @@ void loop() { delay(500); BD_SENSOR_I2C.BD_i2c_stop(); } - - - + + + } \ No newline at end of file diff --git a/klipper/BD_sensor.c b/klipper/BD_sensor.c index 159c4e3d..44d211a8 100644 --- a/klipper/BD_sensor.c +++ b/klipper/BD_sensor.c @@ -324,7 +324,7 @@ void adjust_z_move(void) //diff_step = 0; return; } - + if(diff_step>0){ diff_step--; adjusted_step--; @@ -333,7 +333,7 @@ void adjust_z_move(void) diff_step++; adjusted_step++; } - + for(int i=0;iflags&SF_LAST_DIR); if(dir_t != dir){ gpio_out_toggle_noirq(s->dir_pin); - } - - } + } + + } for(int i=0;istep_pin); - - } - + + } + for(int i=0;iflags&SF_LAST_DIR); if(dir_t != dir){ gpio_out_toggle_noirq(s->dir_pin); - } - - } - + } + + } + ///limite the adjust range if(abs_bd(adjusted_step *1000 / step_adj[0].steps_per_mm,0)>RT_RANGE){//>+-0.3mm //diff_step = 0; @@ -377,7 +377,7 @@ void adjust_z_move(void) diff_step=0; //output("adjust_z_move adjusted_step=%c steps_per_mm=%c mm=%c ", abs_bd(adjusted_step,0),step_adj[0].steps_per_mm,abs_bd(adjusted_step *1000 / step_adj[0].steps_per_mm,0)); } - else{ + else{ if (diff_step>0) diff_step=0; //output("adjust_z_move adjusted_step=-%c steps_per_mm=%c mm=%c ", abs_bd(adjusted_step,0),step_adj[0].steps_per_mm,abs_bd(adjusted_step *1000 / step_adj[0].steps_per_mm,0)); @@ -385,7 +385,7 @@ void adjust_z_move(void) } return; } - + } #define MAX_Z_PLUSE_TIME 1200 @@ -398,7 +398,7 @@ static uint32_t speed_smooth(int32_t adj_len) current_inter=MAX_Z_PLUSE_TIME; acc_count=0; } - + if (total_len <=0) return RT_SAMPLE_TIME; @@ -441,7 +441,7 @@ static uint_fast8_t bd_event(struct timer *t) uint16_t tm=BD_i2c_read(); if(tm<1023){ BD_Data=tm; - { + { adust_Z_calc(BD_Data,s); //sensor_z_old = BD_Data; } @@ -450,7 +450,7 @@ static uint_fast8_t bd_event(struct timer *t) BD_Data=0; } } - + if(e.sample_count || (step_adj[0].cur_z>step_adj[0].adj_z_range) || step_adj[0].adj_z_range==0) timer_ilde = timer_ilde*10; @@ -459,7 +459,7 @@ static uint_fast8_t bd_event(struct timer *t) //bd_tim.time.waketime =timer_read_time()+timer_from_us(300); bd_tim.time.waketime =timer_read_time()+timer_from_us(speed_smooth(0)); } - irq_enable(); + irq_enable(); return SF_RESCHEDULE; } @@ -481,16 +481,16 @@ void timer_bd_uinit(void) void adust_Z_calc(uint16_t sensor_z,struct stepper *s) { - // BD_Data + // BD_Data static int sensor_z_old=0; - if(step_adj[0].zoid==0 || step_adj[0].adj_z_range<=0 + if(step_adj[0].zoid==0 || step_adj[0].adj_z_range<=0 || (step_adj[0].cur_z>step_adj[0].adj_z_range) || sensor_z>=380||BD_read_flag!=1018){ diff_step = 0; return; } - + if(s->count){ //diff_step = 0; return; @@ -554,7 +554,7 @@ command_I2C_BD_send(uint32_t *args) //output("command_I2C_BD_send mcuoid=%c cmd=%c dat=%c", args[0],cmd_c,args[2]); //only read data if(cmd_c==CMD_READ_DATA && args[2]==1){ - + BD_Data=BD_i2c_read(); sendf("I2CBDr oid=%c r=%c", oid_g,BD_Data); } diff --git a/klipper/BDsensor.py b/klipper/BDsensor.py index a09d04f5..6383555a 100644 --- a/klipper/BDsensor.py +++ b/klipper/BDsensor.py @@ -11,6 +11,7 @@ from mcu import MCU, MCU_trsync from . import manual_probe from . import probe + BD_TIMER = 0.600 TRSYNC_TIMEOUT = 0.025 TRSYNC_SINGLE_MCU_TIMEOUT = 0.250 @@ -30,20 +31,21 @@ # Calculate a move's accel_t, cruise_t, and cruise_v def calc_move_time(dist, speed, accel): - axis_r = 1. - if dist < 0.: - axis_r = -1. + axis_r = 1.0 + if dist < 0.0: + axis_r = -1.0 dist = -dist if not accel or not dist: - return axis_r, 0., dist / speed, speed + return axis_r, 0.0, dist / speed, speed max_cruise_v2 = dist * accel - if max_cruise_v2 < speed ** 2: + if max_cruise_v2 < speed**2: speed = math.sqrt(max_cruise_v2) accel_t = speed / accel accel_decel_d = accel_t * speed cruise_t = (dist - accel_decel_d) / speed return axis_r, accel_t, cruise_t, speed + # Helper to obtain a single probe measurement def run_single_probe(probe, gcmd): probe_session = probe.start_probe_session(gcmd) @@ -52,6 +54,7 @@ def run_single_probe(probe, gcmd): probe_session.end_probe_session() return pos + # I2C BD_SENSOR # devices connected to an MCU via an virtual i2c bus(2 any gpio) @@ -68,87 +71,92 @@ def __init__(self, config, mcu_probe): self.name = config.get_name() self.config = config self.mcu_probe = mcu_probe - self.speed = config.getfloat('speed', 5.0, above=0.) - self.lift_speed = config.getfloat('lift_speed', self.speed, above=0.) - self.x_offset = config.getfloat('x_offset', 0.) - self.y_offset = config.getfloat('y_offset', 0.) - self.z_offset = config.getfloat('z_offset') - self.probe_calibrate_z = 0. + self.speed = config.getfloat("speed", 5.0, above=0.0) + self.lift_speed = config.getfloat("lift_speed", self.speed, above=0.0) + self.x_offset = config.getfloat("x_offset", 0.0) + self.y_offset = config.getfloat("y_offset", 0.0) + self.z_offset = config.getfloat("z_offset") + self.probe_calibrate_z = 0.0 self.multi_probe_pending = False self.rapid_scan = False self.last_state = False - self.last_z_result = 0. + self.last_z_result = 0.0 self.homing_speed_tmp = 0 self.gcode_move = self.printer.load_object(config, "gcode_move") # Infer Z position to move to during a probe - if config.has_section('stepper_z'): - zconfig = config.getsection('stepper_z') - self.z_position = zconfig.getfloat('position_min', 0., - note_valid=False) + if config.has_section("stepper_z"): + zconfig = config.getsection("stepper_z") + self.z_position = zconfig.getfloat("position_min", 0.0, note_valid=False) else: - pconfig = config.getsection('printer') - self.z_position = pconfig.getfloat('minimum_z_position', 0., - note_valid=False) + pconfig = config.getsection("printer") + self.z_position = pconfig.getfloat( + "minimum_z_position", 0.0, note_valid=False + ) # Multi-sample support (for improved accuracy) - self.sample_count = config.getint('samples', 1, minval=1) - self.sample_retract_dist = config.getfloat('sample_retract_dist', 5., - above=0.) + self.sample_count = config.getint("samples", 1, minval=1) + self.sample_retract_dist = config.getfloat( + "sample_retract_dist", 5.0, above=0.0 + ) self.samples_result = config.getchoice( - 'samples_result', - {'median': 'median', 'average': 'average'}, - 'average' + "samples_result", {"median": "median", "average": "average"}, "average" ) - self.samples_tolerance = config.getfloat('samples_tolerance', 0.100, - minval=0.) - self.samples_retries = config.getint('samples_tolerance_retries', 0, - minval=0) + self.samples_tolerance = config.getfloat("samples_tolerance", 0.100, minval=0.0) + self.samples_retries = config.getint("samples_tolerance_retries", 0, minval=0) # Register z_virtual_endstop pin - self.printer.lookup_object('pins').register_chip('probe', self) + self.printer.lookup_object("pins").register_chip("probe", self) # Register homing event handlers - self.printer.register_event_handler("homing:homing_move_begin", - self._handle_homing_move_begin) - self.printer.register_event_handler("homing:homing_move_end", - self._handle_homing_move_end) - self.printer.register_event_handler("homing:home_rails_begin", - self._handle_home_rails_begin) - self.printer.register_event_handler("homing:home_rails_end", - self._handle_home_rails_end) - self.printer.register_event_handler("gcode:command_error", - self._handle_command_error) + self.printer.register_event_handler( + "homing:homing_move_begin", self._handle_homing_move_begin + ) + self.printer.register_event_handler( + "homing:homing_move_end", self._handle_homing_move_end + ) + self.printer.register_event_handler( + "homing:home_rails_begin", self._handle_home_rails_begin + ) + self.printer.register_event_handler( + "homing:home_rails_end", self._handle_home_rails_end + ) + self.printer.register_event_handler( + "gcode:command_error", self._handle_command_error + ) # Register PROBE/QUERY_PROBE commands - self.gcode = self.printer.lookup_object('gcode') - self.gcode.register_command('PROBE', self.cmd_PROBE, - desc=self.cmd_PROBE_help) - self.gcode.register_command('QUERY_PROBE', self.cmd_QUERY_PROBE, - desc=self.cmd_QUERY_PROBE_help) - self.gcode.register_command('PROBE_CALIBRATE', - self.cmd_PROBE_CALIBRATE, - desc=self.cmd_PROBE_CALIBRATE_help) - self.gcode.register_command('PROBE_ACCURACY', self.cmd_PROBE_ACCURACY, - desc=self.cmd_PROBE_ACCURACY_help) + self.gcode = self.printer.lookup_object("gcode") + self.gcode.register_command("PROBE", self.cmd_PROBE, desc=self.cmd_PROBE_help) + self.gcode.register_command( + "QUERY_PROBE", self.cmd_QUERY_PROBE, desc=self.cmd_QUERY_PROBE_help + ) self.gcode.register_command( - 'Z_OFFSET_APPLY_PROBE', + "PROBE_CALIBRATE", + self.cmd_PROBE_CALIBRATE, + desc=self.cmd_PROBE_CALIBRATE_help, + ) + self.gcode.register_command( + "PROBE_ACCURACY", self.cmd_PROBE_ACCURACY, desc=self.cmd_PROBE_ACCURACY_help + ) + self.gcode.register_command( + "Z_OFFSET_APPLY_PROBE", self.cmd_Z_OFFSET_APPLY_PROBE, - desc=self.cmd_Z_OFFSET_APPLY_PROBE_help + desc=self.cmd_Z_OFFSET_APPLY_PROBE_help, ) - gcode = self.printer.lookup_object('gcode') + gcode = self.printer.lookup_object("gcode") self.dummy_gcode_cmd = gcode.create_gcode_command("", "", {}) self.reactor = self.printer.get_reactor() - self.bd_sample_timer = self.reactor.register_timer( - self.scan_sample_event) - + self.bd_sample_timer = self.reactor.register_timer(self.scan_sample_event) + def _probe_state_error(self): raise self.printer.command_error( - "Internal probe error - start/end probe session mismatch") + "Internal probe error - start/end probe session mismatch" + ) - def start_probe_session(self, gcmd): - self._probe_times=[] + def start_probe_session(self, gcmd): + self._probe_times = [] if "BED_MESH_CALIBRATE" in gcmd.get_command(): try: if self.mcu_probe.no_stop_probe is not None: self.rapid_scan = True - self.reactor.update_timer(self.bd_sample_timer, self.reactor.NOW) + self.reactor.update_timer(self.bd_sample_timer, self.reactor.NOW) except AttributeError as e: gcmd.respond_info("%s" % str(e)) raise gcmd.error("%s" % str(e)) @@ -158,12 +166,12 @@ def start_probe_session(self, gcmd): self.multi_probe_pending = True self.mcu_probe.results = [] return self - + def pull_probed_results(self): toolhead = self.printer.lookup_object("toolhead") toolhead.get_last_move_time() - if self.rapid_scan == True: - self.bedmesh = self.printer.lookup_object('bed_mesh', None) + if self.rapid_scan == True: + self.bedmesh = self.printer.lookup_object("bed_mesh", None) helperc = self.bedmesh.bmc.probe_mgr.probe_helper while len(self.mcu_probe.results) < len(helperc.probe_points): toolhead.dwell(0.1) @@ -176,31 +184,35 @@ def pull_probed_results(self): def end_probe_session(self): if not self.multi_probe_pending: self._probe_state_error() - self.mcu_probe.results = [] + self.mcu_probe.results = [] self.multi_probe_pending = False self.mcu_probe.multi_probe_end() - + def get_probe_params(self, gcmd=None): if gcmd is None: gcmd = self.dummy_gcode_cmd - probe_speed = gcmd.get_float("PROBE_SPEED", self.speed, above=0.) - lift_speed = gcmd.get_float("LIFT_SPEED", self.lift_speed, above=0.) + probe_speed = gcmd.get_float("PROBE_SPEED", self.speed, above=0.0) + lift_speed = gcmd.get_float("LIFT_SPEED", self.lift_speed, above=0.0) samples = gcmd.get_int("SAMPLES", self.sample_count, minval=1) - sample_retract_dist = gcmd.get_float("SAMPLE_RETRACT_DIST", - self.sample_retract_dist, above=0.) - samples_tolerance = gcmd.get_float("SAMPLES_TOLERANCE", - self.samples_tolerance, minval=0.) - samples_retries = gcmd.get_int("SAMPLES_TOLERANCE_RETRIES", - self.samples_retries, minval=0) + sample_retract_dist = gcmd.get_float( + "SAMPLE_RETRACT_DIST", self.sample_retract_dist, above=0.0 + ) + samples_tolerance = gcmd.get_float( + "SAMPLES_TOLERANCE", self.samples_tolerance, minval=0.0 + ) + samples_retries = gcmd.get_int( + "SAMPLES_TOLERANCE_RETRIES", self.samples_retries, minval=0 + ) samples_result = gcmd.get("SAMPLES_RESULT", self.samples_result) - return {'probe_speed': probe_speed, - 'lift_speed': lift_speed, - 'samples': samples, - 'sample_retract_dist': sample_retract_dist, - 'samples_tolerance': samples_tolerance, - 'samples_tolerance_retries': samples_retries, - 'samples_result': samples_result} - + return { + "probe_speed": probe_speed, + "lift_speed": lift_speed, + "samples": samples, + "sample_retract_dist": sample_retract_dist, + "samples_tolerance": samples_tolerance, + "samples_tolerance_retries": samples_retries, + "samples_result": samples_result, + } def _handle_homing_move_begin(self, hmove): if self.mcu_probe in hmove.get_mcu_endstops(): @@ -217,21 +229,26 @@ def _handle_home_rails_begin(self, homing_state, rails): self.mcu_probe.multi_probe_begin() self.multi_probe_pending = True for i, rail in enumerate(rails): - if (self.mcu_probe.collision_homing == 1 - and rail.homing_retract_dist == 0): + if ( + self.mcu_probe.collision_homing == 1 + and rail.homing_retract_dist == 0 + ): self.homing_speed_tmp = rail.homing_speed rail.homing_speed = rail.second_homing_speed - self.gcode.respond_info("Homing_speed at %.3f" % (rail.homing_speed)) + self.gcode.respond_info( + "Homing_speed at %.3f" % (rail.homing_speed) + ) def _handle_home_rails_end(self, homing_state, rails): endstops = [es for rail in rails for es, name in rail.get_endstops()] if self.mcu_probe in endstops: for i, rail in enumerate(rails): - if (self.homing_speed_tmp > rail.homing_speed - and rail.homing_retract_dist == 0): + if ( + self.homing_speed_tmp > rail.homing_speed + and rail.homing_retract_dist == 0 + ): rail.homing_speed = self.homing_speed_tmp self.multi_probe_end() - def _handle_command_error(self): try: @@ -249,27 +266,26 @@ def multi_probe_end(self): self.mcu_probe.multi_probe_end() def setup_pin(self, pin_type, pin_params): - if pin_type != 'endstop' or pin_params['pin'] != 'z_virtual_endstop': - raise pins.error("Probe virtual endstop only" - "useful as endstop pin") - if pin_params['invert'] or pin_params['pullup']: + if pin_type != "endstop" or pin_params["pin"] != "z_virtual_endstop": + raise pins.error("Probe virtual endstop only" "useful as endstop pin") + if pin_params["invert"] or pin_params["pullup"]: raise pins.error("Can not pullup/invert probe virtual endstop") return self.mcu_probe def get_lift_speed(self, gcmd=None): if gcmd is not None: - return gcmd.get_float("LIFT_SPEED", self.lift_speed, above=0.) + return gcmd.get_float("LIFT_SPEED", self.lift_speed, above=0.0) return self.lift_speed def get_offsets(self): return self.x_offset, self.y_offset, self.z_offset def _probe_enstop(self, speed): - toolhead = self.printer.lookup_object('toolhead') + toolhead = self.printer.lookup_object("toolhead") curtime = self.printer.get_reactor().monotonic() - if 'z' not in toolhead.get_status(curtime)['homed_axes']: + if "z" not in toolhead.get_status(curtime)["homed_axes"]: raise self.printer.command_error("Must home before probe") - phoming = self.printer.lookup_object('homing') + phoming = self.printer.lookup_object("homing") pos = toolhead.get_position() pos[2] = self.z_position try: @@ -282,23 +298,23 @@ def _probe_enstop(self, speed): # Allow axis_twist_compensation to update results self.printer.send_event("probe:update_results", epos) # add z compensation to probe position - gcode = self.printer.lookup_object('gcode') - gcode.respond_info("probe at %.3f,%.3f is z=%.6f" - % (epos[0], epos[1], epos[2])) + gcode = self.printer.lookup_object("gcode") + gcode.respond_info("probe at %.3f,%.3f is z=%.6f" % (epos[0], epos[1], epos[2])) return epos[:3] def _probe(self, speed): self.mcu_probe.homing = 0 if self.mcu_probe.endstop_pin_num != self.mcu_probe.sda_pin_num: return self._probe_enstop(speed) - toolhead = self.printer.lookup_object('toolhead') + toolhead = self.printer.lookup_object("toolhead") curtime = self.printer.get_reactor().monotonic() - if 'z' not in toolhead.get_status(curtime)['homed_axes']: + if "z" not in toolhead.get_status(curtime)["homed_axes"]: raise self.printer.command_error("Must home before probe") - phoming = self.printer.lookup_object('homing') + phoming = self.printer.lookup_object("homing") pos = toolhead.get_position() - self.mcu_probe.reactor.update_timer(self.mcu_probe.bd_update_timer, - self.mcu_probe.reactor.NEVER) + self.mcu_probe.reactor.update_timer( + self.mcu_probe.bd_update_timer, self.mcu_probe.reactor.NEVER + ) pos[2] = self.z_position try: epos = phoming.probing_move(self.mcu_probe, pos, speed) @@ -311,9 +327,9 @@ def _probe(self, speed): toolhead.wait_moves() time.sleep(0.1) b_value = self.mcu_probe.BD_Sensor_Read(2) - b_value = b_value+self.mcu_probe.BD_Sensor_Read(2) - b_value = b_value+self.mcu_probe.BD_Sensor_Read(2) - b_value = b_value/3 + b_value = b_value + self.mcu_probe.BD_Sensor_Read(2) + b_value = b_value + self.mcu_probe.BD_Sensor_Read(2) + b_value = b_value / 3 pos_new = toolhead.get_position() epos[2] = pos_new[2] - b_value + self.mcu_probe.endstop_bdsensor_offset # Allow axis_twist_compensation to update results @@ -322,16 +338,15 @@ def _probe(self, speed): "probe at %.3f,%.3f is z=%.6f (pos:%.6f - bd:%.3f)" % (epos[0], epos[1], epos[2], pos_new[2], b_value) ) - #self.mcu_probe.homeing = 0 + # self.mcu_probe.homeing = 0 return epos[:3] def _move(self, coord, speed): - self.printer.lookup_object('toolhead').manual_move(coord, speed) + self.printer.lookup_object("toolhead").manual_move(coord, speed) def _calc_mean(self, positions): count = float(len(positions)) - return [sum([pos[i] for pos in positions]) / count - for i in range(3)] + return [sum([pos[i] for pos in positions]) / count for i in range(3)] def _calc_median(self, positions): z_sorted = sorted(positions, key=(lambda p: p[2])) @@ -340,17 +355,17 @@ def _calc_median(self, positions): # odd number of samples return z_sorted[middle] # even number of samples - return self._calc_mean(z_sorted[middle - 1:middle + 1]) + return self._calc_mean(z_sorted[middle - 1 : middle + 1]) - def _lookup_toolhead_pos(self, pos_time): - toolhead = self.printer.lookup_object('toolhead') + toolhead = self.printer.lookup_object("toolhead") kin = toolhead.get_kinematics() - kin_spos = {s.get_name(): s.mcu_to_commanded_position( - s.get_past_mcu_position(pos_time)) - for s in kin.get_steppers()} + kin_spos = { + s.get_name(): s.mcu_to_commanded_position(s.get_past_mcu_position(pos_time)) + for s in kin.get_steppers() + } return kin.calc_position(kin_spos) - + def scan_sample_event(self, eventtime): toolhead = self.printer.lookup_object("toolhead") while self._probe_times: @@ -358,81 +373,91 @@ def scan_sample_event(self, eventtime): while 1: systime = toolhead.reactor.monotonic() est_print_time = toolhead.mcu.estimated_print_time(systime) - if est_print_time>=pos_time: + if est_print_time >= pos_time: pos = self._lookup_toolhead_pos(pos_time) - intd = self.mcu_probe.BD_Sensor_Read(0) + intd = self.mcu_probe.BD_Sensor_Read(0) pos[2] = pos[2] - intd + self.mcu_probe.endstop_bdsensor_offset self.mcu_probe.results.append(pos) # Allow axis_twist_compensation to update results self.printer.send_event("probe:update_results", pos) # limit the message output to the console else it may take a lot of time if len(self.mcu_probe.results) < 500: - self.gcode.respond_info("probe at %.3f,%.3f is z=%.6f" - % (pos[0], pos[1], pos[2])) + self.gcode.respond_info( + "probe at %.3f,%.3f is z=%.6f" % (pos[0], pos[1], pos[2]) + ) break toolhead.reactor.pause(systime + 0.002) self._probe_times.pop(0) - + return eventtime + 0.005 - - def _scan_lookahead_cb(self, printtime): + def _scan_lookahead_cb(self, printtime): self._probe_times.append(printtime) def run_probe(self, gcmd): toolhead = self.printer.lookup_object("toolhead") if self.rapid_scan == True: if len(self._probe_times) == 0: - toolhead.wait_moves() + toolhead.wait_moves() toolhead.register_lookahead_callback(self._scan_lookahead_cb) return - speed = gcmd.get_float("PROBE_SPEED", self.speed, above=0.) + speed = gcmd.get_float("PROBE_SPEED", self.speed, above=0.0) lift_speed = self.get_lift_speed(gcmd) sample_count = gcmd.get_int("SAMPLES", self.sample_count, minval=1) - sample_retract_dist = gcmd.get_float("SAMPLE_RETRACT_DIST", - self.sample_retract_dist, - above=0.) - samples_tolerance = gcmd.get_float("SAMPLES_TOLERANCE", - self.samples_tolerance, minval=0.) - samples_retries = gcmd.get_int("SAMPLES_TOLERANCE_RETRIES", - self.samples_retries, minval=0) + sample_retract_dist = gcmd.get_float( + "SAMPLE_RETRACT_DIST", self.sample_retract_dist, above=0.0 + ) + samples_tolerance = gcmd.get_float( + "SAMPLES_TOLERANCE", self.samples_tolerance, minval=0.0 + ) + samples_retries = gcmd.get_int( + "SAMPLES_TOLERANCE_RETRIES", self.samples_retries, minval=0 + ) samples_result = gcmd.get("SAMPLES_RESULT", self.samples_result) must_notify_multi_probe = not self.multi_probe_pending if must_notify_multi_probe: self.start_probe_session(gcmd) - probexy = self.printer.lookup_object('toolhead').get_position()[:2] + probexy = self.printer.lookup_object("toolhead").get_position()[:2] retries = 0 positions = [] - toolhead = self.printer.lookup_object('toolhead') + toolhead = self.printer.lookup_object("toolhead") # gcmd.respond_info("speed:%.3f"%speed) while len(positions) < sample_count: # Probe position try: - if ((self.mcu_probe is not None) and - (("BED_MESH_CALIBRATE" in gcmd.get_command()) or - (("QUAD_GANTRY_LEVEL" in gcmd.get_command() or - "Z_TILT_ADJUST" in gcmd.get_command()) - and self.mcu_probe.QGL_Tilt_Probe == 0))): + if (self.mcu_probe is not None) and ( + ("BED_MESH_CALIBRATE" in gcmd.get_command()) + or ( + ( + "QUAD_GANTRY_LEVEL" in gcmd.get_command() + or "Z_TILT_ADJUST" in gcmd.get_command() + ) + and self.mcu_probe.QGL_Tilt_Probe == 0 + ) + ): # pos = self._probe(speed) toolhead.wait_moves() time.sleep(0.1) pos = toolhead.get_position() intd = self.mcu_probe.BD_Sensor_Read(0) pos[2] = pos[2] - intd + self.mcu_probe.endstop_bdsensor_offset - self.gcode.respond_info("probe at %.3f,%.3f is z=%.6f" - % (pos[0], pos[1], pos[2])) + self.gcode.respond_info( + "probe at %.3f,%.3f is z=%.6f" % (pos[0], pos[1], pos[2]) + ) # return pos[:3] positions.append(pos[:3]) # Check samples tolerance z_positions = [p[2] for p in positions] if max(z_positions) - min(z_positions) > samples_tolerance: if retries >= samples_retries: - raise gcmd.error("Probe samples " - "exceed samples_tolerance") - gcmd.respond_info("Probe samples exceed tolerance." - "Retrying...") + raise gcmd.error( + "Probe samples " "exceed samples_tolerance" + ) + gcmd.respond_info( + "Probe samples exceed tolerance." "Retrying..." + ) retries += 1 positions = [] continue @@ -456,10 +481,10 @@ def run_probe(self, gcmd): if must_notify_multi_probe: self.multi_probe_end() # Calculate and return result - if samples_result == 'median': + if samples_result == "median": return self._calc_median(positions) epos = self._calc_mean(positions) - #epos = calc_probe_z_average(positions, params['samples_result']) + # epos = calc_probe_z_average(positions, params['samples_result']) self.mcu_probe.results.append(epos) cmd_PROBE_help = "Probe Z-height at current XY position" @@ -472,41 +497,52 @@ def cmd_PROBE(self, gcmd): cmd_QUERY_PROBE_help = "Return the status of the z-probe" def cmd_QUERY_PROBE(self, gcmd): - toolhead = self.printer.lookup_object('toolhead') + toolhead = self.printer.lookup_object("toolhead") print_time = toolhead.get_last_move_time() res = self.mcu_probe.query_endstop(print_time) self.last_state = res gcmd.respond_info("probe: %s" % (["open", "TRIGGERED"][not not res],)) def get_status(self, eventtime): - return {'name': self.name, - 'last_query': self.last_state, - 'last_z_result': self.last_z_result} + return { + "name": self.name, + "last_query": self.last_state, + "last_z_result": self.last_z_result, + } cmd_PROBE_ACCURACY_help = "Probe Z-height accuracy at current XY position" def cmd_PROBE_ACCURACY(self, gcmd): params = self.get_probe_params(gcmd) - speed = gcmd.get_float("PROBE_SPEED", self.speed, above=0.) + speed = gcmd.get_float("PROBE_SPEED", self.speed, above=0.0) lift_speed = self.get_lift_speed(gcmd) sample_count = gcmd.get_int("SAMPLES", 10, minval=1) - sample_retract_dist = gcmd.get_float("SAMPLE_RETRACT_DIST", - self.sample_retract_dist, above=0.) - toolhead = self.printer.lookup_object('toolhead') + sample_retract_dist = gcmd.get_float( + "SAMPLE_RETRACT_DIST", self.sample_retract_dist, above=0.0 + ) + toolhead = self.printer.lookup_object("toolhead") pos = toolhead.get_position() pos[2] = 1.0 - gcmd.respond_info("PROBE_ACCURACY at X:%.3f Y:%.3f Z:%.3f" - " (samples=%d retract=%.3f" - " speed=%.1f lift_speed=%.1f)\n" - % (pos[0], pos[1], pos[2], - sample_count, sample_retract_dist, - speed, lift_speed)) + gcmd.respond_info( + "PROBE_ACCURACY at X:%.3f Y:%.3f Z:%.3f" + " (samples=%d retract=%.3f" + " speed=%.1f lift_speed=%.1f)\n" + % ( + pos[0], + pos[1], + pos[2], + sample_count, + sample_retract_dist, + speed, + lift_speed, + ) + ) # Probe bed sample_count times - + # toolhead.manual_move([None, None, pos[2]], speed) # toolhead.wait_moves() fo_params = dict(gcmd.get_command_parameters()) - fo_params['SAMPLES'] = '1' + fo_params["SAMPLES"] = "1" fo_gcmd = self.gcode.create_gcode_command("", "", fo_params) probe_session = self.start_probe_session(fo_gcmd) positions = [] @@ -517,8 +553,8 @@ def cmd_PROBE_ACCURACY(self, gcmd): probe_num += 1 # Retract pos = toolhead.get_position() - liftpos = [None, None, pos[2] + params['sample_retract_dist']] - self._move(liftpos, params['lift_speed']) + liftpos = [None, None, pos[2] + params["sample_retract_dist"]] + self._move(liftpos, params["lift_speed"]) positions = probe_session.pull_probed_results() probe_session.end_probe_session() @@ -531,7 +567,7 @@ def cmd_PROBE_ACCURACY(self, gcmd): # calculate the standard deviation deviation_sum = 0 for i in range(len(positions)): - deviation_sum += pow(positions[i][2] - avg_value, 2.) + deviation_sum += pow(positions[i][2] - avg_value, 2.0) sigma = (deviation_sum / len(positions)) ** 0.5 # Show information gcmd.respond_info( @@ -550,8 +586,8 @@ def probe_calibrate_finalize(self, kin_pos): "The SAVE_CONFIG command will update the printer config file\n" "with the above and restart the printer." % (self.name, z_offset) ) - configfile = self.printer.lookup_object('configfile') - configfile.set(self.name, 'z_offset', "%.3f" % z_offset) + configfile = self.printer.lookup_object("configfile") + configfile.set(self.name, "z_offset", "%.3f" % z_offset) cmd_PROBE_CALIBRATE_help = "Calibrate the probe's z_offset" @@ -563,21 +599,23 @@ def cmd_PROBE_CALIBRATE(self, gcmd): curpos = run_single_probe(self, gcmd) # Move away from the bed self.probe_calibrate_z = curpos[2] - curpos[2] += 5. + curpos[2] += 5.0 self._move(curpos, lift_speed) # Move the nozzle over the probe point x_offset, y_offset, z_offset = self.get_offsets() curpos[0] += x_offset curpos[1] += y_offset - self._move(curpos, params['probe_speed']) + self._move(curpos, params["probe_speed"]) # Start manual probe - manual_probe.ManualProbeHelper(self.printer, gcmd, - self.probe_calibrate_finalize) + manual_probe.ManualProbeHelper( + self.printer, gcmd, self.probe_calibrate_finalize + ) + cmd_Z_OFFSET_APPLY_PROBE_help = "Adjust the probe's z_offset" def cmd_Z_OFFSET_APPLY_PROBE(self, gcmd): - offset = self.gcode_move.get_status()['homing_origin'].z - configfile = self.printer.lookup_object('configfile') + offset = self.gcode_move.get_status()["homing_origin"].z + configfile = self.printer.lookup_object("configfile") if offset == 0: self.gcode.respond_info("Nothing to do: Z Offset is 0") else: @@ -585,9 +623,9 @@ def cmd_Z_OFFSET_APPLY_PROBE(self, gcmd): self.gcode.respond_info( "%s: z_offset: %.3f\n" "The SAVE_CONFIG command will update the printer config file\n" - "with the above and restart the printer." - % (self.name, new_calibrate)) - configfile.set(self.name, 'z_offset', "%.3f" % (new_calibrate,)) + "with the above and restart the printer." % (self.name, new_calibrate) + ) + configfile.set(self.name, "z_offset", "%.3f" % (new_calibrate,)) # BDsensor wrapper that enables probe specific features @@ -596,72 +634,78 @@ def cmd_Z_OFFSET_APPLY_PROBE(self, gcmd): class BDsensorEndstopWrapper: def __init__(self, config): self.printer = config.get_printer() - self.printer.register_event_handler('klippy:mcu_identify', self._handle_mcu_identify) + self.printer.register_event_handler( + "klippy:mcu_identify", self._handle_mcu_identify + ) self.config = config self.name = config.get_name() - self.g28_cmd = config.get('homing_cmd', 'G28') - self.z_adjust = config.getfloat('z_adjust', 0., minval=-0.3, below=0.3) - self.z_offset = config.getfloat('z_offset', 0., minval=-0.6, maxval=0.6) - self.position_endstop = config.getfloat('position_endstop', 0.7, - minval=0.5, below=2.5) + self.g28_cmd = config.get("homing_cmd", "G28") + self.z_adjust = config.getfloat("z_adjust", 0.0, minval=-0.3, below=0.3) + self.z_offset = config.getfloat("z_offset", 0.0, minval=-0.6, maxval=0.6) + self.position_endstop = config.getfloat( + "position_endstop", 0.7, minval=0.5, below=2.5 + ) if self.z_adjust > self.position_endstop: - raise self.printer.command_error("The 'z_adjust' cannot be greater" - " than 'position_endstop' in " - "section [BDsensor]") + raise self.printer.command_error( + "The 'z_adjust' cannot be greater" + " than 'position_endstop' in " + "section [BDsensor]" + ) if self.z_offset > self.position_endstop: - raise self.printer.command_error("The 'z_offset' cannot be greater" - " than 'position_endstop' in " - "section [BDsensor]") - self.stow_on_each_sample = config.getboolean( - 'deactivate_on_each_sample', True) - self.no_stop_probe = config.get('no_stop_probe', None) - self.collision_homing = config.getint('collision_homing', 0) - self.collision_calibrate = config.getint('collision_calibrate', 0) - self.rt_sample_time = config.getint('rt_sample_time', 0)#ms - self.rt_max_range = config.getfloat('rt_max_range', 0, minval=0) - self.QGL_Tilt_Probe = config.getint('QGL_Tilt_Probe', 1) - self.switch_mode_sample_time = config.getfloat('SWITCH_MODE_SAMPLE_TIME', 0.006) - self.speed = config.getfloat('speed', 3.0, above=0.) - - gcode_macro = self.printer.load_object(config, - 'gcode_macro') - self.activate_gcode = \ - gcode_macro.load_template(config, 'activate_gcode', '') - self.deactivate_gcode = \ - gcode_macro.load_template(config, 'deactivate_gcode', '') + raise self.printer.command_error( + "The 'z_offset' cannot be greater" + " than 'position_endstop' in " + "section [BDsensor]" + ) + self.stow_on_each_sample = config.getboolean("deactivate_on_each_sample", True) + self.no_stop_probe = config.get("no_stop_probe", None) + self.collision_homing = config.getint("collision_homing", 0) + self.collision_calibrate = config.getint("collision_calibrate", 0) + self.rt_sample_time = config.getint("rt_sample_time", 0) # ms + self.rt_max_range = config.getfloat("rt_max_range", 0, minval=0) + self.QGL_Tilt_Probe = config.getint("QGL_Tilt_Probe", 1) + self.switch_mode_sample_time = config.getfloat("SWITCH_MODE_SAMPLE_TIME", 0.006) + self.speed = config.getfloat("speed", 3.0, above=0.0) + + gcode_macro = self.printer.load_object(config, "gcode_macro") + self.activate_gcode = gcode_macro.load_template(config, "activate_gcode", "") + self.deactivate_gcode = gcode_macro.load_template( + config, "deactivate_gcode", "" + ) self.collision_calibrating = 0 self.switch_mode = 0 - self.printer.register_event_handler("stepper_enable:motor_off", - self.event_motor_off) - ppins = self.printer.lookup_object('pins') + self.printer.register_event_handler( + "stepper_enable:motor_off", self.event_motor_off + ) + ppins = self.printer.lookup_object("pins") # self.mcu_pwm = ppins.setup_pin('pwm', config.get('scl_pin')) - self.bdversion = '' + self.bdversion = "" # Command timing - self.next_cmd_time = self.action_end_time = 0. - pin = config.get('sda_pin') + self.next_cmd_time = self.action_end_time = 0.0 + pin = config.get("sda_pin") pin_params = ppins.lookup_pin(pin, can_invert=False, can_pullup=True) - mcu = pin_params['chip'] - self.sda_pin_num = pin_params['pin'] + mcu = pin_params["chip"] + self.sda_pin_num = pin_params["pin"] self.mcu = mcu # print("b2:%s"%mcu) pin_s = [] try: - pin_s = config.get('scl_pin') + pin_s = config.get("scl_pin") except Exception as e: try: - pin_s = config.get('clk_pin') + pin_s = config.get("clk_pin") except Exception as e: raise self.printer.command_error("%s" % str(e)) pass pin_params = ppins.lookup_pin(pin_s, can_invert=False, can_pullup=True) - mcu = pin_params['chip'] - scl_pin_num = pin_params['pin'] + mcu = pin_params["chip"] + scl_pin_num = pin_params["pin"] # print("b3:%s"%mcu) # pin_params['pullup']=2 # self.mcu_endstop = mcu.setup_pin('endstop', pin_params) - self._invert = pin_params['invert'] + self._invert = pin_params["invert"] self.oid = self.mcu.create_oid() @@ -671,11 +715,11 @@ def __init__(self, config): self.endstop_pin_num = self.sda_pin_num self.endstop_bdsensor_offset = 0 try: - pin = config.get('endstop_pin') + pin = config.get("endstop_pin") pin_params = ppins.lookup_pin(pin, can_invert=True, can_pullup=True) - self.endstop_pin_num = pin_params['pin'] - self.mcu_endstop = pin_params['chip'] - self._invert_endstop = pin_params['invert'] + self.endstop_pin_num = pin_params["pin"] + self.mcu_endstop = pin_params["chip"] + self._invert_endstop = pin_params["invert"] if self.mcu_endstop is not self.mcu: self.oid_endstop = self.mcu_endstop.create_oid() except Exception as e: @@ -687,45 +731,56 @@ def __init__(self, config): self.trapq_append = ffi_lib.trapq_append self.trapq_finalize_moves = ffi_lib.trapq_finalize_moves self.stepper_kinematics = ffi_main.gc( - ffi_lib.cartesian_stepper_alloc(b'x'), ffi_lib.free) + ffi_lib.cartesian_stepper_alloc(b"x"), ffi_lib.free + ) self.config_fmt = ( - "config_I2C_BD oid=%d sda_pin=%s scl_pin=%s delay=%s" - " h_pos=%d z_adjust=%d estop_pin=%s" - % (self.oid, self.sda_pin_num, scl_pin_num, config.get('delay'), self.position_endstop * 100, self.z_adjust * 100,self.endstop_pin_num)) + "config_I2C_BD oid=%d sda_pin=%s scl_pin=%s delay=%s" + " h_pos=%d z_adjust=%d estop_pin=%s" + % ( + self.oid, + self.sda_pin_num, + scl_pin_num, + config.get("delay"), + self.position_endstop * 100, + self.z_adjust * 100, + self.endstop_pin_num, + ) + ) self.mcu.add_config_cmd(self.config_fmt) self.I2C_BD_send_cmd = None # MCU_BD_I2C_from_config(self.mcu,config) # Register commands - self.gcode = self.printer.lookup_object('gcode') - self.width_filament = config.getint('width_filament', 0) + self.gcode = self.printer.lookup_object("gcode") + self.width_filament = config.getint("width_filament", 0) if self.width_filament == 0: - self.gcode.register_command('M102', self.cmd_M102) - self.gcode.register_command('BDSENSOR_VERSION', self.BD_version) - self.gcode.register_command('BDSENSOR_CALIBRATE', self.BD_calibrate) - self.gcode.register_command('BDSENSOR_READ_CALIBRATION', self.BD_read_calibration) - self.gcode.register_command('BDSENSOR_DISTANCE', self.bd_distance) - self.gcode.register_command('BDSENSOR_SET', self.bd_set) + self.gcode.register_command("M102", self.cmd_M102) + self.gcode.register_command("BDSENSOR_VERSION", self.BD_version) + self.gcode.register_command("BDSENSOR_CALIBRATE", self.BD_calibrate) + self.gcode.register_command( + "BDSENSOR_READ_CALIBRATION", self.BD_read_calibration + ) + self.gcode.register_command("BDSENSOR_DISTANCE", self.bd_distance) + self.gcode.register_command("BDSENSOR_SET", self.bd_set) self.gcode_move = self.printer.load_object(config, "gcode_move") - self.gcode = self.printer.lookup_object('gcode') - self.bedmesh = self.printer.lookup_object('bed_mesh', None) + self.gcode = self.printer.lookup_object("gcode") + self.bedmesh = self.printer.lookup_object("bed_mesh", None) # Wrappers self.bd_value = 10.24 self.results = [] self.finish_home_complete = self.wait_trigger_complete = None # multi probes state - self.multi = 'OFF' + self.multi = "OFF" self.mcu.register_config_callback(self.build_config) self.adjust_range = 0 self.old_count = 1000 self.homing = 0 self.reactor = self.printer.get_reactor() - self.bd_update_timer = self.reactor.register_timer( - self.bd_update_event) - + self.bd_update_timer = self.reactor.register_timer(self.bd_update_event) + self.status_dis = None # try: # self.status_dis=self.printer.lookup_object('display_status') @@ -747,38 +802,39 @@ def build_config(self): self.I2C_BD_send_cmd = self.mcu.lookup_query_command( "I2CBD oid=%c c=%c d=%c", "I2CBDr oid=%c r=%c", - oid=self.oid, cq=self.cmd_queue) + oid=self.oid, + cq=self.cmd_queue, + ) - self.mcu.register_response(self._handle_BD_Update, - "BD_Update", self.oid) - self.mcu.register_response(self.handle_probe_Update, - "X_probe_Update", self.oid) + self.mcu.register_response(self._handle_BD_Update, "BD_Update", self.oid) + self.mcu.register_response(self.handle_probe_Update, "X_probe_Update", self.oid) self.mcu_endstop.add_config_cmd( "BDendstop_home oid=%d clock=0 sample_ticks=0 sample_count=0" " rest_ticks=0 pin_value=0 trsync_oid=0 trigger_reason=0" - " endstop_pin=%s sw=0 sw_val=0" - % (self.oid_endstop, self.endstop_pin_num), on_restart=True) + " endstop_pin=%s sw=0 sw_val=0" % (self.oid_endstop, self.endstop_pin_num), + on_restart=True, + ) # Lookup commands self._home_cmd = self.mcu_endstop.lookup_command( "BDendstop_home oid=%c clock=%u sample_ticks=%u sample_count=%c" " rest_ticks=%u pin_value=%c trsync_oid=%c trigger_reason=%c" " endstop_pin=%c sw=%c sw_val=%c", - cq=cmd_queue + cq=cmd_queue, ) def I2C_BD_send(self, cmd, data=0): data = int(data) if cmd == CMD_READ_DATA or cmd == CMD_READ_ENDSTOP: pr = self.I2C_BD_send_cmd.send([self.oid, cmd, data]) - #self.gcode.respond_info(f"{pr}") - return int(pr['r']) + # self.gcode.respond_info(f"{pr}") + return int(pr["r"]) else: return self.I2C_BD_send_cmd.send([self.oid, cmd, data]) def _handle_BD_Update(self, params): try: - self.bd_value = int(params['distance_val']) / 100.00 + self.bd_value = int(params["distance_val"]) / 100.00 if self.status_dis is not None: strd = str(self.bd_value) + "mm" if self.bd_value == 10.24: @@ -790,17 +846,17 @@ def _handle_BD_Update(self, params): pass def handle_probe_Update(self, params): - count = int(params['distance_val'].split(b' ')[1]) + count = int(params["distance_val"].split(b" ")[1]) self.old_count = count try: - self.results.append(int(params['distance_val'].split(b' ')[0])) + self.results.append(int(params["distance_val"].split(b" ")[0])) except ValueError as e: pass def _force_enable(self, stepper): - self.toolhead = self.printer.lookup_object('toolhead') + self.toolhead = self.printer.lookup_object("toolhead") print_time = self.toolhead.get_last_move_time() - stepper_enable = self.printer.lookup_object('stepper_enable') + stepper_enable = self.printer.lookup_object("stepper_enable") enable = stepper_enable.lookup_enable(stepper.get_name()) was_enable = enable.is_motor_enabled() STALL_TIME = 0.100 @@ -809,17 +865,29 @@ def _force_enable(self, stepper): self.toolhead.dwell(STALL_TIME) return was_enable - def manual_move(self, stepper, dist, speed, accel=0.): - self.toolhead = self.printer.lookup_object('toolhead') + def manual_move(self, stepper, dist, speed, accel=0.0): + self.toolhead = self.printer.lookup_object("toolhead") self.toolhead.flush_step_generation() prev_sk = stepper.set_stepper_kinematics(self.stepper_kinematics) prev_trapq = stepper.set_trapq(self.trapq) - stepper.set_position((0., 0., 0.)) + stepper.set_position((0.0, 0.0, 0.0)) axis_r, accel_t, cruise_t, cruise_v = calc_move_time(dist, speed, accel) print_time = self.toolhead.get_last_move_time() self.trapq_append( - self.trapq, print_time, accel_t, cruise_t, accel_t, - 0., 0., 0., axis_r, 0., 0., 0., cruise_v, accel + self.trapq, + print_time, + accel_t, + cruise_t, + accel_t, + 0.0, + 0.0, + 0.0, + axis_r, + 0.0, + 0.0, + 0.0, + cruise_v, + accel, ) print_time = print_time + accel_t + cruise_t + accel_t stepper.generate_steps(print_time) @@ -831,39 +899,61 @@ def manual_move(self, stepper, dist, speed, accel=0.): def bd_set_cur_z(self, hgt, s_log): if s_log == 1: - self.gcode.respond_info("Curent z:%.2f (gcode_z:%.2f - (z_offset:%.2f - z_offset_adj:%.2f))" % (hgt-(self.z_offset-self.z_offset_adj),hgt,self.z_offset,self.z_offset_adj)) - if (hgt-self.z_offset)<=0: - self.gcode.respond_info("The real_time_adjust is ignored because current z:%.2f (gcode_z:%.2f - (z_offset:%.2f - z_offset_adj:%.2f)) <=0" % (hgt-(self.z_offset-self.z_offset_adj),hgt,self.z_offset,self.z_offset_adj)) - #self.gcode.respond_info("Since current z <0 ") - return; - hgt = hgt-(self.z_offset-self.z_offset_adj) - hgt=int(hgt*1000) + self.gcode.respond_info( + "Curent z:%.2f (gcode_z:%.2f - (z_offset:%.2f - z_offset_adj:%.2f))" + % ( + hgt - (self.z_offset - self.z_offset_adj), + hgt, + self.z_offset, + self.z_offset_adj, + ) + ) + if (hgt - self.z_offset) <= 0: + self.gcode.respond_info( + "The real_time_adjust is ignored because current z:%.2f (gcode_z:%.2f - (z_offset:%.2f - z_offset_adj:%.2f)) <=0" + % ( + hgt - (self.z_offset - self.z_offset_adj), + hgt, + self.z_offset, + self.z_offset_adj, + ) + ) + # self.gcode.respond_info("Since current z <0 ") + return + hgt = hgt - (self.z_offset - self.z_offset_adj) + hgt = int(hgt * 1000) self.I2C_BD_send(1026, hgt) - def event_motor_off(self,print_time=0): + + def event_motor_off(self, print_time=0): if self.adjust_range != 0: self.BD_real_time(0) - def bd_update_z(self,z): - self.toolhead = self.printer.lookup_object('toolhead') + def bd_update_z(self, z): + self.toolhead = self.printer.lookup_object("toolhead") kin = self.toolhead.get_kinematics() for stepper in kin.get_steppers(): - if stepper.is_active_axis('z') or stepper.is_active_axis('a') or stepper.is_active_axis('b') or stepper.is_active_axis('c'): - self.bd_set_cur_z(z,1) + if ( + stepper.is_active_axis("z") + or stepper.is_active_axis("a") + or stepper.is_active_axis("b") + or stepper.is_active_axis("c") + ): + self.bd_set_cur_z(z, 1) break self.I2C_BD_send(CMD_DISTANCE_MODE) - + def bd_update_event(self, eventtime): - z=self.gcode_move.last_position[2] - self.gcode_move.base_position[2] + z = self.gcode_move.last_position[2] - self.gcode_move.base_position[2] if self.homing == 1: self.reactor.update_timer(self.bd_update_timer, self.reactor.NEVER) gcode_move = self.printer.lookup_object("gcode_move") - offset = gcode_move.get_status()['homing_origin'].z + offset = gcode_move.get_status()["homing_origin"].z if self.z_offset_adj != offset and offset != 0: self.z_offset_adj = offset self.bd_update_z(z) - if self.z_last != z and self.homing == 0: + if self.z_last != z and self.homing == 0: self.z_last = z self.bd_update_z(z) return eventtime + BD_TIMER @@ -875,40 +965,40 @@ def cmd_M102(self, gcmd, wait=False): def BD_Sensor_Read(self, fore_r): if fore_r > 0: self.I2C_BD_send(CMD_DISTANCE_MODE) # prepare to read distance data - intr = self.I2C_BD_send(CMD_READ_DATA, 1) # read data + intr = self.I2C_BD_send(CMD_READ_DATA, 1) # read data if intr >= DATA_ERROR: intr = self.I2C_BD_send(CMD_READ_DATA, 1) self.bd_value = intr / 100.00 if fore_r == 0: if self.bd_value >= 10.24: - self.gcode.respond_info("Bed Distance Sensor " - "data error0:%.2f" - % self.bd_value) - raise self.printer.command_error("Bed Distance Sensor " - "data error0:%.2f" - % self.bd_value) + self.gcode.respond_info( + "Bed Distance Sensor " "data error0:%.2f" % self.bd_value + ) + raise self.printer.command_error( + "Bed Distance Sensor " "data error0:%.2f" % self.bd_value + ) elif self.bd_value > 3.8: - self.gcode.respond_info("Bed Distance Sensor, " - "out of range.:%.2f " - % self.bd_value) - raise self.printer.command_error("Bed Distance Sensor, " - "out of range.:%.2f " - % self.bd_value) + self.gcode.respond_info( + "Bed Distance Sensor, " "out of range.:%.2f " % self.bd_value + ) + raise self.printer.command_error( + "Bed Distance Sensor, " "out of range.:%.2f " % self.bd_value + ) elif fore_r == 2: if self.bd_value >= 10.24: - self.gcode.respond_info("Bed Distance Sensor " - "data error2:%.2f" - % self.bd_value) - raise self.printer.command_error("Bed Distance Sensor " - "data error2:%.2f" - % self.bd_value) + self.gcode.respond_info( + "Bed Distance Sensor " "data error2:%.2f" % self.bd_value + ) + raise self.printer.command_error( + "Bed Distance Sensor " "data error2:%.2f" % self.bd_value + ) return self.bd_value + self.z_offset - def BD_version(self, gcmd,r_lenght=20): + def BD_version(self, gcmd, r_lenght=20): self.I2C_BD_send(CMD_READ_VERSION) # 1016 // // read sensor version - # self.I2C_BD_send(CMD_READ_VERSION) - self.toolhead = self.printer.lookup_object('toolhead') + # self.I2C_BD_send(CMD_READ_VERSION) + self.toolhead = self.printer.lookup_object("toolhead") ncount1 = 0 x = [] while 1: @@ -922,63 +1012,77 @@ def BD_version(self, gcmd,r_lenght=20): ncount1 = ncount1 + 1 if ncount1 >= r_lenght: self.I2C_BD_send(CMD_DISTANCE_MODE) - res = ''.join(map(chr, x)) + res = "".join(map(chr, x)) self.bdversion = res break self.I2C_BD_send(CMD_DISTANCE_MODE) - #self.I2C_BD_send(CMD_DISTANCE_MODE) + # self.I2C_BD_send(CMD_DISTANCE_MODE) self.switch_mode = 1 - if "V1.0 " in self.bdversion \ - or "V1.1 " in self.bdversion \ - or "V1.2 " in self.bdversion: + if ( + "V1.0 " in self.bdversion + or "V1.1 " in self.bdversion + or "V1.2 " in self.bdversion + ): self.switch_mode = 0 if "V1." in self.bdversion: - self.gcode.respond_info("BDsensorVer:%s,switch_mode=%d," - "collision_homing=%d,collision_cal=%d" - % (self.bdversion, self.switch_mode, - self.collision_homing, - self.collision_calibrate)) + self.gcode.respond_info( + "BDsensorVer:%s,switch_mode=%d," + "collision_homing=%d,collision_cal=%d" + % ( + self.bdversion, + self.switch_mode, + self.collision_homing, + self.collision_calibrate, + ) + ) else: - self.gcode.respond_info("No data or corrupt data from BDsensor(%s), " - "Please check connection"%self.bdversion) + self.gcode.respond_info( + "No data or corrupt data from BDsensor(%s), " + "Please check connection" % self.bdversion + ) def BD_calibrate(self, gcmd): if "V1." not in self.bdversion: - self.BD_version(self.gcode,20) + self.BD_version(self.gcode, 20) if self.switch_mode == 1 and self.collision_calibrate == 1: self.collision_calibrating = 1 - #gcmd.respond_info("Homing") + # gcmd.respond_info("Homing") self.gcode.run_script_from_command("BED_MESH_CLEAR") curtime = self.printer.get_reactor().monotonic() - if 'x' not in self.toolhead.get_status(curtime)['homed_axes']: - gstr=self.g28_cmd - gcmd.respond_info("Homing all:"+gstr) + if "x" not in self.toolhead.get_status(curtime)["homed_axes"]: + gstr = self.g28_cmd + gcmd.respond_info("Homing all:" + gstr) self.gcode.run_script_from_command(gstr) - elif 'z' not in self.toolhead.get_status(curtime)['homed_axes']: - gstr=self.g28_cmd+" Z" - gcmd.respond_info("Homing z:"+gstr) + elif "z" not in self.toolhead.get_status(curtime)["homed_axes"]: + gstr = self.g28_cmd + " Z" + gcmd.respond_info("Homing z:" + gstr) self.gcode.run_script_from_command(gstr) self.gcode.run_script_from_command("G1 Z0") self.toolhead.wait_moves() gcmd.respond_info("Calibrating, don't power off the printer") - self.toolhead = self.printer.lookup_object('toolhead') - # kin = self.toolhead.get_kinematics() + self.toolhead = self.printer.lookup_object("toolhead") + # kin = self.toolhead.get_kinematics() self.I2C_BD_send(CMD_DISTANCE_RAWDATA_TYPE) self.I2C_BD_send(CMD_DISTANCE_RAWDATA_TYPE) raw_d = self.I2C_BD_send(CMD_READ_DATA, 1) - if raw_d > 600 : + if raw_d > 600: if raw_d == DATA_ERROR: - raise self.printer.command_error("Unable to communicate with bdsensor,%d"%raw_d) - raise self.printer.command_error("BDsensor is too far from the bed:%d"%raw_d) + raise self.printer.command_error( + "Unable to communicate with bdsensor,%d" % raw_d + ) + raise self.printer.command_error( + "BDsensor is too far from the bed:%d" % raw_d + ) self.I2C_BD_send(CMD_DISTANCE_MODE) - + self.I2C_BD_send(CMD_START_CALIBRATE) self.I2C_BD_send(CMD_START_CALIBRATE) self.gcode.run_script_from_command("SET_KINEMATIC_POSITION Z=0") curtime = self.printer.get_reactor().monotonic() - if 'z' not in self.toolhead.get_status(curtime)['homed_axes']: - raise self.printer.command_error("make sure [force_move]" - " enable_force_move: true # in the printer.cfg") + if "z" not in self.toolhead.get_status(curtime)["homed_axes"]: + raise self.printer.command_error( + "make sure [force_move]" " enable_force_move: true # in the printer.cfg" + ) self.toolhead.dwell(0.2) gcmd.respond_info("Please Wait... ") z_pos = 0 @@ -1005,34 +1109,39 @@ def BD_calibrate(self, gcmd): self.toolhead.dwell(1) self.BD_read_calibration(gcmd) gcmd.respond_info("Calibrate Finished!") - #gcmd.respond_info("You can send command " + # gcmd.respond_info("You can send command " # "BDSENSOR_READ_CALIBRATION " # "to check the calibration data") self.z_adjust = 0 - #configfile = self.printer.lookup_object('configfile') - #configfile.set(self.name, 'z_adjust', "0.0") + # configfile = self.printer.lookup_object('configfile') + # configfile.set(self.name, 'z_adjust', "0.0") break self.I2C_BD_send(CMD_DISTANCE_MODE) self.I2C_BD_send(CMD_DISTANCE_MODE) self.collision_calibrating = 0 - #self.toolhead.dwell(1) - #self.BD_read_calibration(gcmd) + # self.toolhead.dwell(1) + # self.BD_read_calibration(gcmd) + def BD_read_calibration(self, gcmd): self.I2C_BD_send(CMD_START_READ_CALIBRATE_DATA) # tart read raw calibrate data self.I2C_BD_send(CMD_START_READ_CALIBRATE_DATA) - self.toolhead = self.printer.lookup_object('toolhead') + self.toolhead = self.printer.lookup_object("toolhead") ncount1 = 0 while 1: intd = self.I2C_BD_send(CMD_READ_DATA, 1) - gcmd.respond_info("%d at %.1fmm"%(intd,ncount1/10.0)) + gcmd.respond_info("%d at %.1fmm" % (intd, ncount1 / 10.0)) if ncount1 <= 3 and intd > 500: - gcmd.respond_raw("BDSensor mounted too high!" - "0.4mm to 2.4mm from BED at" - "zero position is recommended") + gcmd.respond_raw( + "BDSensor mounted too high!" + "0.4mm to 2.4mm from BED at" + "zero position is recommended" + ) # break if intd < 45: - gcmd.respond_raw("BDSensor mounted too close! please mount" - "the BDsensor 0.2~0.4mm higher") + gcmd.respond_raw( + "BDSensor mounted too close! please mount" + "the BDsensor 0.2~0.4mm higher" + ) # break self.toolhead.dwell(0.03) ncount1 = ncount1 + 1 @@ -1050,7 +1159,7 @@ def bd_distance(self, gcmd): strd = "BDsensor:Out of measure Range or too close to the bed" gcmd.respond_raw(strd) try: - self.status_dis = self.printer.lookup_object('display_status') + self.status_dis = self.printer.lookup_object("display_status") self.status_dis.message = strd except Exception as e: pass @@ -1059,11 +1168,13 @@ def bd_distance(self, gcmd): def bd_set(self, gcmd): cmd_bd = 0.0 - cmd_bd = gcmd.get_float('Z_ADJUST', None) + cmd_bd = gcmd.get_float("Z_ADJUST", None) if cmd_bd is not None: - gcmd.respond_info("z_adjust:%f, recommend to move the nozzle " - "close to bed and calibrate again the BDsensor" - "instead of chang z_adjust" % cmd_bd) + gcmd.respond_info( + "z_adjust:%f, recommend to move the nozzle " + "close to bed and calibrate again the BDsensor" + "instead of chang z_adjust" % cmd_bd + ) if cmd_bd >= 0.3: cmd_bd = 0.29 gcmd.respond_info("it has been set to the max value 0.29") @@ -1071,40 +1182,44 @@ def bd_set(self, gcmd): cmd_bd = -0.29 gcmd.respond_info("it has been set to the min value -0.29") self.z_adjust = cmd_bd - configfile = self.printer.lookup_object('configfile') - configfile.set(self.name, 'z_adjust', "%.3f" % cmd_bd) - gcmd.respond_info("The SAVE_CONFIG command will update" - "the printer config") + configfile = self.printer.lookup_object("configfile") + configfile.set(self.name, "z_adjust", "%.3f" % cmd_bd) + gcmd.respond_info( + "The SAVE_CONFIG command will update" "the printer config" + ) return - cmd_bd = gcmd.get_float('REAL_TIME_HEIGHT', None) + cmd_bd = gcmd.get_float("REAL_TIME_HEIGHT", None) if cmd_bd is not None: - self.BD_real_time(cmd_bd) + self.BD_real_time(cmd_bd) return - cmd_bd = gcmd.get_int('NO_STOP_PROBE', None) + cmd_bd = gcmd.get_int("NO_STOP_PROBE", None) if cmd_bd is not None: - configfile = self.printer.lookup_object('configfile') - configfile.set(self.name, 'no_stop_probe', "%d" % cmd_bd) - gcmd.respond_info("no_stop_probe is setted:%d The SAVE_CONFIG" - "command will update the printer config", cmd_bd) + configfile = self.printer.lookup_object("configfile") + configfile.set(self.name, "no_stop_probe", "%d" % cmd_bd) + gcmd.respond_info( + "no_stop_probe is setted:%d The SAVE_CONFIG" + "command will update the printer config", + cmd_bd, + ) return - cmd_bd = gcmd.get_float('QGL_TILT_PROBE', None) + cmd_bd = gcmd.get_float("QGL_TILT_PROBE", None) if cmd_bd is not None: self.QGL_Tilt_Probe = cmd_bd - self.gcode.respond_info("QGL_Tilt_Probe:%d"%self.QGL_Tilt_Probe) + self.gcode.respond_info("QGL_Tilt_Probe:%d" % self.QGL_Tilt_Probe) return - cmd_bd = gcmd.get_float('COLLISION_HOMING', None) + cmd_bd = gcmd.get_float("COLLISION_HOMING", None) if cmd_bd is not None: self.collision_homing = cmd_bd return - cmd_bd = gcmd.get_float('COLLISION_CALIBRATING', None) + cmd_bd = gcmd.get_float("COLLISION_CALIBRATING", None) if cmd_bd is not None: self.collision_calibrating = cmd_bd return - cmd_bd = gcmd.get_float('POSITION_ENDSTOP', None) + cmd_bd = gcmd.get_float("POSITION_ENDSTOP", None) if cmd_bd is not None: self.position_endstop = cmd_bd return @@ -1114,35 +1229,43 @@ def BD_real_time(self, bd_height): bd_height = 3 elif bd_height < 0.0: bd_height = 0 - self.gcode.respond_info("Real time leveling height:%.2f ( %.2f - z_offset:%.2f ) "%(bd_height-self.z_offset,bd_height,self.z_offset)) - + self.gcode.respond_info( + "Real time leveling height:%.2f ( %.2f - z_offset:%.2f ) " + % (bd_height - self.z_offset, bd_height, self.z_offset) + ) + if bd_height == 0: self.adjust_range = 0 else: - bd_height = bd_height-self.z_offset - self.adjust_range = int((bd_height+0.01)*1000) + bd_height = bd_height - self.z_offset + self.adjust_range = int((bd_height + 0.01) * 1000) self.I2C_BD_send(CMD_DISTANCE_MODE) - self.toolhead = self.printer.lookup_object('toolhead') + self.toolhead = self.printer.lookup_object("toolhead") kin = self.toolhead.get_kinematics() z_index = 0 for stepper in kin.get_steppers(): - if stepper.is_active_axis('z') or stepper.is_active_axis('a') or stepper.is_active_axis('b') or stepper.is_active_axis('c'): - steps_per_mm = 1.0/stepper.get_step_dist() - #z = self.gcode_move.last_position[2] - z=self.gcode_move.last_position[2] - self.gcode_move.base_position[2] - #stepper._query_mcu_position() + if ( + stepper.is_active_axis("z") + or stepper.is_active_axis("a") + or stepper.is_active_axis("b") + or stepper.is_active_axis("c") + ): + steps_per_mm = 1.0 / stepper.get_step_dist() + # z = self.gcode_move.last_position[2] + z = self.gcode_move.last_position[2] - self.gcode_move.base_position[2] + # stepper._query_mcu_position() invert_dir, orig_invert_dir = stepper.get_dir_inverted() - #z = int(z*1000) + # z = int(z*1000) self.I2C_BD_send(1025, z_index) - #self.I2C_BD_send(1026, z) - self.bd_set_cur_z(z,0) + # self.I2C_BD_send(1026, z) + self.bd_set_cur_z(z, 0) self.I2C_BD_send(1027, self.adjust_range) self.I2C_BD_send(1028, orig_invert_dir) self.I2C_BD_send(1029, steps_per_mm) if self.rt_sample_time > 0: self.I2C_BD_send(1031, self.rt_sample_time) if self.rt_max_range > 0: - self.I2C_BD_send(1032, self.rt_max_range*1000) + self.I2C_BD_send(1032, self.rt_max_range * 1000) self.I2C_BD_send(1030, stepper.get_oid()) z_index = z_index + 1 self.I2C_BD_send(CMD_DISTANCE_MODE) @@ -1150,39 +1273,46 @@ def BD_real_time(self, bd_height): self.reactor.update_timer(self.bd_update_timer, self.reactor.NEVER) else: self.reactor.update_timer(self.bd_update_timer, self.reactor.NOW) - + def process_M102(self, gcmd): self.process_m102 = 1 cmd_bd = 0 try: - cmd_bd = gcmd.get_int('S', None) + cmd_bd = gcmd.get_int("S", None) except Exception as e: pass return - self.toolhead = self.printer.lookup_object('toolhead') + self.toolhead = self.printer.lookup_object("toolhead") if cmd_bd == -6: self.BD_calibrate(gcmd) elif cmd_bd == -5: self.BD_read_calibration(gcmd) elif cmd_bd == -1: - self.BD_version(gcmd,20) + self.BD_version(gcmd, 20) elif cmd_bd == -2: # gcode M102 S-2 read distance data self.bd_distance(gcmd) elif cmd_bd == -7: - self.I2C_BD_send(CMD_DISTANCE_RAWDATA_TYPE) + self.I2C_BD_send(CMD_DISTANCE_RAWDATA_TYPE) strd = "Raw data:" + str(self.I2C_BD_send(CMD_READ_DATA, 1)) self.I2C_BD_send(CMD_DISTANCE_MODE) self.bd_value = self.BD_Sensor_Read(1) - strd = strd + ", Then we can calculate the distance by comparing to the calibration data:"+str(self.bd_value) + "mm" - gcmd.respond_raw(strd) + strd = ( + strd + + ", Then we can calculate the distance by comparing to the calibration data:" + + str(self.bd_value) + + "mm" + ) + gcmd.respond_raw(strd) return elif cmd_bd == -8: self.I2C_BD_send(CMD_REBOOT_SENSOR) elif cmd_bd == -9: self.I2C_BD_send(CMD_SWITCH_MODE) self.I2C_BD_send(str(int(self.position_endstop * 100))) - self.gcode.respond_info("in switch mode, the endstop position is" - "%.3f mm" % self.position_endstop) + self.gcode.respond_info( + "in switch mode, the endstop position is" + "%.3f mm" % self.position_endstop + ) return else: return @@ -1191,9 +1321,9 @@ def process_M102(self, gcmd): # self.process_m102=0 def _handle_mcu_identify(self): - kin = self.printer.lookup_object('toolhead').get_kinematics() + kin = self.printer.lookup_object("toolhead").get_kinematics() for stepper in kin.get_steppers(): - if stepper.is_active_axis('z'): + if stepper.is_active_axis("z"): self.add_stepper(stepper) def raise_probe(self): @@ -1208,8 +1338,8 @@ def query_endstop(self, print_time=0): if self.endstop_pin_num != self.sda_pin_num and self._invert_endstop: if params == 0: params = 1 - else : - params = 0 + else: + params = 0 self.gcode.respond_info("params:%d" % params) return params @@ -1222,58 +1352,61 @@ def add_stepper(self, stepper): trsync.add_stepper(stepper) # Check for unsupported multi-mcu shared stepper rails sname = stepper.get_name() - if sname.startswith('stepper_'): + if sname.startswith("stepper_"): for ot in self._trsyncs: for s in ot.get_steppers(): if ot is not trsync and s.get_name().startswith(sname[:9]): cerror = self.mcu.get_printer().config_error - raise cerror("Multi-mcu homing not supported on" - " multi-mcu shared axis") + raise cerror( + "Multi-mcu homing not supported on" " multi-mcu shared axis" + ) def get_steppers(self): return [s for trsync in self._trsyncs for s in trsync.get_steppers()] - def home_start(self, print_time, sample_time, sample_count, rest_time, - triggered=True): + def home_start( + self, print_time, sample_time, sample_count, rest_time, triggered=True + ): collision_value = int(self.position_endstop * 100) if "V1." not in self.bdversion: - self.BD_version(self.gcode,5) - #self.homing = 1 + self.BD_version(self.gcode, 5) + # self.homing = 1 if self.switch_mode == 1: - #self.I2C_BD_send(CMD_SWITCH_MODE) + # self.I2C_BD_send(CMD_SWITCH_MODE) sample_time = self.switch_mode_sample_time sample_count = 2 - if self.homing == 1 and (self.collision_homing == 1 - or self.collision_calibrating == 1): - #self.I2C_BD_send(1) + if self.homing == 1 and ( + self.collision_homing == 1 or self.collision_calibrating == 1 + ): + # self.I2C_BD_send(1) collision_value = 1 - #else: - # self.I2C_BD_send(int(self.position_endstop * 100)) - #self.gcode.respond_info("home_pos:%s" % str(int(self.position_endstop * 100))) - # time.sleep(0.01) + # else: + # self.I2C_BD_send(int(self.position_endstop * 100)) + # self.gcode.respond_info("home_pos:%s" % str(int(self.position_endstop * 100))) + # time.sleep(0.01) else: - sample_time = .03 + sample_time = 0.03 sample_count = 1 clock = self.mcu_endstop.print_time_to_clock(print_time) - rest_ticks = \ - self.mcu_endstop.print_time_to_clock(print_time+rest_time) - clock + rest_ticks = ( + self.mcu_endstop.print_time_to_clock(print_time + rest_time) - clock + ) self._rest_ticks = rest_ticks reactor = self.mcu_endstop.get_printer().get_reactor() - self.wait_trigger_complete = \ - reactor.register_callback(self.wait_for_trigger) + self.wait_trigger_complete = reactor.register_callback(self.wait_for_trigger) self.trigger_completion = reactor.completion() expire_timeout = TRSYNC_TIMEOUT if len(self._trsyncs) == 1: expire_timeout = TRSYNC_SINGLE_MCU_TIMEOUT for i, trsync in enumerate(self._trsyncs): report_offset = float(i) / len(self._trsyncs) - trsync.start(print_time, report_offset, - self.trigger_completion, expire_timeout) + trsync.start( + print_time, report_offset, self.trigger_completion, expire_timeout + ) self.etrsync = self._trsyncs[0] ffi_main, ffi_lib = chelper.get_ffi() - ffi_lib.trdispatch_start(self._trdispatch, - self.etrsync.REASON_HOST_REQUEST) + ffi_lib.trdispatch_start(self._trdispatch, self.etrsync.REASON_HOST_REQUEST) self._home_cmd.send( [ @@ -1286,16 +1419,17 @@ def home_start(self, print_time, sample_time, sample_count, rest_time, self.etrsync.get_oid(), self.etrsync.REASON_ENDSTOP_HIT, self.endstop_pin_num, - self.switch_mode,collision_value + self.switch_mode, + collision_value, ], - reqclock=clock + reqclock=clock, ) self.finish_home_complete = self.trigger_completion return self.trigger_completion def wait_for_trigger(self, eventtime): self.trigger_completion.wait() - if self.multi == 'OFF': + if self.multi == "OFF": self.raise_probe() def home_wait(self, home_end_time): @@ -1304,30 +1438,34 @@ def home_wait(self, home_end_time): if self.mcu_endstop.is_fileoutput(): self.trigger_completion.complete(True) self.trigger_completion.wait() - self._home_cmd.send([self.oid_endstop, 0, 0, 0, 0, 0, 0, 0, - self.endstop_pin_num,0,0]) + self._home_cmd.send( + [self.oid_endstop, 0, 0, 0, 0, 0, 0, 0, self.endstop_pin_num, 0, 0] + ) ffi_main, ffi_lib = chelper.get_ffi() ffi_lib.trdispatch_stop(self._trdispatch) res = [trsync.stop() for trsync in self._trsyncs] if any([r == etrsync.REASON_COMMS_TIMEOUT for r in res]): - return -1. + return -1.0 if res[0] != etrsync.REASON_ENDSTOP_HIT: - return 0. + return 0.0 if self.mcu_endstop.is_fileoutput(): return home_end_time return home_end_time def multi_probe_begin(self): - # self.BD_Sensor_Read(2)# check the if the BDsensor is working + # self.BD_Sensor_Read(2)# check the if the BDsensor is working curtime = self.printer.get_reactor().monotonic() - self.toolhead = self.printer.lookup_object('toolhead') + self.toolhead = self.printer.lookup_object("toolhead") kin_status = self.toolhead.get_kinematics().get_status(curtime) - if 'z' not in kin_status['homed_axes'] and self.endstop_pin_num == self.sda_pin_num: - #self.gcode.respond_info("Check bd sensor") - self.BD_Sensor_Read(2)# check the if the BDsensor is working + if ( + "z" not in kin_status["homed_axes"] + and self.endstop_pin_num == self.sda_pin_num + ): + # self.gcode.respond_info("Check bd sensor") + self.BD_Sensor_Read(2) # check the if the BDsensor is working if self.stow_on_each_sample: return - self.multi = 'FIRST' + self.multi = "FIRST" def adjust_probe_up(self, up_steps, second_steps, logd): homepos = self.toolhead.get_position() @@ -1335,7 +1473,7 @@ def adjust_probe_up(self, up_steps, second_steps, logd): intr = self.I2C_BD_send(CMD_READ_DATA, 1) intr_old = intr if intr > 720: - self.gcode.respond_info("warning: triggered in air, %d"%intr) + self.gcode.respond_info("warning: triggered in air, %d" % intr) pos_old = homepos[2] while 1: homepos[2] += up_steps @@ -1343,11 +1481,11 @@ def adjust_probe_up(self, up_steps, second_steps, logd): self.toolhead.wait_moves() time.sleep(0.05) raw_d = self.I2C_BD_send(CMD_READ_DATA, 1) - if (raw_d - intr) >= (up_steps*100*2): + if (raw_d - intr) >= (up_steps * 100 * 2): if second_steps == 0: break pos_old_1 = homepos[2] - homepos[2] -= 0.1 # (up_steps*1.5) + homepos[2] -= 0.1 # (up_steps*1.5) self.toolhead.manual_move([None, None, homepos[2]], 2) self.toolhead.wait_moves() intr = raw_d @@ -1357,24 +1495,30 @@ def adjust_probe_up(self, up_steps, second_steps, logd): self.toolhead.wait_moves() time.sleep(0.05) raw_d = self.I2C_BD_send(CMD_READ_DATA, 1) - #homepos_n = self.toolhead.get_position() - if (raw_d - intr) >= (second_steps*100*2) or homepos[2] >= pos_old_1: + # homepos_n = self.toolhead.get_position() + if (raw_d - intr) >= (second_steps * 100 * 2) or homepos[ + 2 + ] >= pos_old_1: if logd == 1: temp = 0 try: - pheaters = self.printer.lookup_object('heaters') - heaters = pheaters.lookup_heater('heater_bed') - temp, target = heaters.get_temp(self.printer.get_reactor().monotonic()) + pheaters = self.printer.lookup_object("heaters") + heaters = pheaters.lookup_heater("heater_bed") + temp, target = heaters.get_temp( + self.printer.get_reactor().monotonic() + ) except Exception as e: pass - self.gcode.respond_info("Raw data:%d at 0 mm, BDsensor to bed: %.4f mm, Bed: %.1fC, z_offset: %.3f" - % (raw_d,raw_d*0.004,temp,self.z_offset)) - return homepos[2]-pos_old,raw_d-intr_old + self.gcode.respond_info( + "Raw data:%d at 0 mm, BDsensor to bed: %.4f mm, Bed: %.1fC, z_offset: %.3f" + % (raw_d, raw_d * 0.004, temp, self.z_offset) + ) + return homepos[2] - pos_old, raw_d - intr_old break intr = raw_d break - intr = raw_d - return 0,0 + intr = raw_d + return 0, 0 def adjust_probe_down(self, down_steps): homepos = self.toolhead.get_position() @@ -1388,79 +1532,79 @@ def adjust_probe_down(self, down_steps): self.toolhead.wait_moves() time.sleep(0.05) raw_d = self.I2C_BD_send(CMD_READ_DATA, 1) - #self.gcode.respond_info(" %d "%raw_d) - if (intr - raw_d) < down_steps*200 and raw_d < 600: - #self.gcode.respond_info(" stop at %d "%raw_d) - break; + # self.gcode.respond_info(" %d "%raw_d) + if (intr - raw_d) < down_steps * 200 and raw_d < 600: + # self.gcode.respond_info(" stop at %d "%raw_d) + break intr = raw_d - - - def adjust_probe(self): - self.toolhead = self.printer.lookup_object('toolhead') + self.toolhead = self.printer.lookup_object("toolhead") homepos = self.toolhead.get_position() self.I2C_BD_send(CMD_DISTANCE_RAWDATA_TYPE) self.I2C_BD_send(CMD_DISTANCE_RAWDATA_TYPE) - adj_z,adj_raw = self.adjust_probe_up(0.1,0,1) - #if adj_z <= 0.15: # and adj_raw >= 6: - + adj_z, adj_raw = self.adjust_probe_up(0.1, 0, 1) + # if adj_z <= 0.15: # and adj_raw >= 6: + self.adjust_probe_down(0.1) - adj_z,adj_raw = self.adjust_probe_up(0.05,0.01,0) - + adj_z, adj_raw = self.adjust_probe_up(0.05, 0.01, 0) + self.adjust_probe_down(0.05) - adj_z,adj_raw = self.adjust_probe_up(0.05,0.005,1) - - #if adj_z <= 0.1: # and adj_raw >= 6: + adj_z, adj_raw = self.adjust_probe_up(0.05, 0.005, 1) + + # if adj_z <= 0.1: # and adj_raw >= 6: # self.gcode.respond_info("re-adjusting") # self.adjust_probe_down(0.1) - # adj_z,adj_raw = self.adjust_probe_up(0.05,0.01,1) + # adj_z,adj_raw = self.adjust_probe_up(0.05,0.01,1) self.bd_value = self.BD_Sensor_Read(2) self.I2C_BD_send(CMD_DISTANCE_MODE) def multi_probe_end(self): - self.toolhead = self.printer.lookup_object('toolhead') - homepos = self.toolhead.get_position() + self.toolhead = self.printer.lookup_object("toolhead") + homepos = self.toolhead.get_position() if self.endstop_pin_num == self.sda_pin_num: - - if self.switch_mode == 1 \ - and self.homing == 1 \ - and (self.collision_homing == 1 - or self.collision_calibrating == 1): - + + if ( + self.switch_mode == 1 + and self.homing == 1 + and (self.collision_homing == 1 or self.collision_calibrating == 1) + ): + self.adjust_probe() - #homepos[2] = 0 + # homepos[2] = 0 if self.collision_calibrating != 1: - # homepos[2] = 0 + self.z_offset + 0.5 - self.I2C_BD_send(CMD_DISTANCE_MODE) + # homepos[2] = 0 + self.z_offset + 0.5 + self.I2C_BD_send(CMD_DISTANCE_MODE) homepos = self.toolhead.get_position() - homepos[2] +=0.5 + homepos[2] += 0.5 self.toolhead.manual_move([None, None, homepos[2]], 2) self.toolhead.wait_moves() self.bd_value = self.BD_Sensor_Read(2) time.sleep(0.1) - homepos[2] -=0.5 + homepos[2] -= 0.5 self.toolhead.manual_move([None, None, homepos[2]], 2) self.toolhead.wait_moves() self.gcode.respond_info("bd_value at %.3f mm" % self.bd_value) homepos[2] = 0 + self.z_offset - if abs(self.bd_value-self.z_offset-0.5)>0.05: - self.gcode.respond_info("Detect the plate changed or others, the BD sensor needs recalibration %.3f" % (self.bd_value-0.5)) - # self.toolhead.manual_move([None, None, homepos[2]+10], 2) + if abs(self.bd_value - self.z_offset - 0.5) > 0.05: + self.gcode.respond_info( + "Detect the plate changed or others, the BD sensor needs recalibration %.3f" + % (self.bd_value - 0.5) + ) + # self.toolhead.manual_move([None, None, homepos[2]+10], 2) self.gcode.run_script_from_command("SET_KINEMATIC_POSITION Z=0") self.gcode.run_script_from_command("M102 S-6") - + self.homing = 0 return - - + else: homepos[2] = 0 self.toolhead.set_position(homepos) elif self.homing == 1: self.I2C_BD_send(CMD_DISTANCE_MODE) time.sleep(0.1) - #self.gcode.respond_info("multi_probe_end") + # self.gcode.respond_info("multi_probe_end") self.bd_value = self.BD_Sensor_Read(2) if self.bd_value > (self.position_endstop + 2): self.gcode.respond_info("triggered at %.3f mm" % self.bd_value) @@ -1468,38 +1612,42 @@ def multi_probe_end(self): time.sleep(0.9) self.bd_value = self.BD_Sensor_Read(2) if self.bd_value > (self.position_endstop + 0.7): - raise self.printer.command_error("Home z failed! " - "the triggered at " - "%.3fmm" % self.bd_value) + raise self.printer.command_error( + "Home z failed! " + "the triggered at " + "%.3fmm" % self.bd_value + ) if self.bd_value <= 0: self.gcode.respond_info("warning:triggered at 0mm") # time.sleep(0.1) self.endstop_bdsensor_offset = 0 if self.sda_pin_num is not self.endstop_pin_num: self.endstop_bdsensor_offset = homepos[2] - self.bd_value - self.gcode.respond_info("offset of endstop to bdsensor %.3fmm" - % self.endstop_bdsensor_offset) + self.gcode.respond_info( + "offset of endstop to bdsensor %.3fmm" + % self.endstop_bdsensor_offset + ) else: homepos[2] = self.bd_value self.toolhead.set_position(homepos) # time.sleep(0.1) - #self.gcode.respond_info("Z triggered at %.3f mm,auto adjusted." + # self.gcode.respond_info("Z triggered at %.3f mm,auto adjusted." # % self.bd_value) self.homing = 0 if self.stow_on_each_sample: return self.raise_probe() - self.multi = 'OFF' + self.multi = "OFF" def probe_prepare(self, hmove): - if self.multi == 'OFF' or self.multi == 'FIRST': + if self.multi == "OFF" or self.multi == "FIRST": self.lower_probe() - if self.multi == 'FIRST': - self.multi = 'ON' + if self.multi == "FIRST": + self.multi = "ON" def probe_finish(self, hmove): self.I2C_BD_send(CMD_DISTANCE_MODE) - if self.multi == 'OFF': + if self.multi == "OFF": self.raise_probe() def get_position_endstop(self): @@ -1509,5 +1657,5 @@ def get_position_endstop(self): def load_config(config): bdl = BDsensorEndstopWrapper(config) - config.get_printer().add_object('probe', BDPrinterProbe(config, bdl)) + config.get_printer().add_object("probe", BDPrinterProbe(config, bdl)) return bdl diff --git a/klipper/install_BDsensor.sh b/klipper/install_BDsensor.sh index 324e9aa4..b9459d77 100755 --- a/klipper/install_BDsensor.sh +++ b/klipper/install_BDsensor.sh @@ -3,7 +3,7 @@ HOME_DIR="${HOME}/klipper" if [ -d "$1" ] ; then - + echo "$1" HOME_DIR=""$1"/klipper" fi diff --git a/klipper/uninstall.sh b/klipper/uninstall.sh index 0180b6ad..5c27bf0e 100755 --- a/klipper/uninstall.sh +++ b/klipper/uninstall.sh @@ -3,7 +3,7 @@ HOME_DIR="${HOME}/klipper" if [ -d "$1" ] ; then - + echo "$1" HOME_DIR=""$1"/klipper" fi From 671054af5535f8db10263305680b3858237c22ab Mon Sep 17 00:00:00 2001 From: Reubertt Date: Sat, 24 Jan 2026 22:15:21 +0000 Subject: [PATCH 2/3] chore: formated code with black --- klipper/width_bdsensor.py | 104 ++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/klipper/width_bdsensor.py b/klipper/width_bdsensor.py index 88a1c831..7b4e26fa 100644 --- a/klipper/width_bdsensor.py +++ b/klipper/width_bdsensor.py @@ -13,50 +13,49 @@ from . import BDsensor + class WidthSensorBDsensor: def __init__(self, config): self.printer = config.get_printer() self.config = config self.reactor = self.printer.get_reactor() - self.gcode = self.printer.lookup_object('gcode') - self.width_filament = config.getint('width_filament', 0) - self.MEASUREMENT_INTERVAL_MM=config.getint('measurement_interval',10) + self.gcode = self.printer.lookup_object("gcode") + self.width_filament = config.getint("width_filament", 0) + self.MEASUREMENT_INTERVAL_MM = config.getint("measurement_interval", 10) self.use_current_dia_while_delay = config.getboolean( - 'use_current_dia_while_delay', False) + "use_current_dia_while_delay", False + ) self.nominal_filament_dia = config.getfloat( - 'default_nominal_filament_diameter', 1.75) - self.measurement_delay = config.getfloat('measurement_delay', 1) - self.measurement_max_difference = config.getfloat('max_difference', 0.2) - self.max_diameter = (self.nominal_filament_dia - + self.measurement_max_difference) - self.min_diameter = (self.nominal_filament_dia - - self.measurement_max_difference) - self.diameter =self.nominal_filament_dia - self.is_active =config.getboolean('enable', False) - self.runout_dia_min = config.getfloat('min_diameter', 1.0) - self.runout_dia_max = config.getfloat('max_diameter', self.max_diameter) - self.is_active = False #config.getboolean('enable', False) + "default_nominal_filament_diameter", 1.75 + ) + self.measurement_delay = config.getfloat("measurement_delay", 1) + self.measurement_max_difference = config.getfloat("max_difference", 0.2) + self.max_diameter = self.nominal_filament_dia + self.measurement_max_difference + self.min_diameter = self.nominal_filament_dia - self.measurement_max_difference + self.diameter = self.nominal_filament_dia + self.is_active = config.getboolean("enable", False) + self.runout_dia_min = config.getfloat("min_diameter", 1.0) + self.runout_dia_max = config.getfloat("max_diameter", self.max_diameter) + self.is_active = False # config.getboolean('enable', False) self.extrude_factor_update_timer = self.reactor.register_timer( - self.extrude_factor_update_event) - self.gcode.register_command('ENABLE_FILAMENT_WIDTH_SENSOR', - self.cmd_enable) - self.gcode.register_command('DISABLE_FILAMENT_WIDTH_SENSOR', - self.cmd_disable) - self.gcode.register_command('CLEAR_FILAMENT_WIDTH_SENSOR', - self.cmd_clear) + self.extrude_factor_update_event + ) + self.gcode.register_command("ENABLE_FILAMENT_WIDTH_SENSOR", self.cmd_enable) + self.gcode.register_command("DISABLE_FILAMENT_WIDTH_SENSOR", self.cmd_disable) + self.gcode.register_command("CLEAR_FILAMENT_WIDTH_SENSOR", self.cmd_clear) self.printer.register_event_handler("klippy:ready", self.handle_ready) self.zero_pose = 0 self.filament_array = [] self.runout_helper = filament_switch_sensor.RunoutHelper(config) self.bdsensor = BDsensor.BDsensorEndstopWrapper(config) # Initialization + def handle_ready(self): # Load printer objects - self.toolhead = self.printer.lookup_object('toolhead') + self.toolhead = self.printer.lookup_object("toolhead") # Start extrude factor update timer - self.reactor.update_timer(self.extrude_factor_update_timer, - self.reactor.NOW) + self.reactor.update_timer(self.extrude_factor_update_timer, self.reactor.NOW) def cmd_clear(self, gcmd): self.zero_pose = 0 @@ -68,8 +67,9 @@ def cmd_enable(self, gcmd): else: self.is_active = True # Start extrude factor update timer - self.reactor.update_timer(self.extrude_factor_update_timer, - self.reactor.NOW) + self.reactor.update_timer( + self.extrude_factor_update_timer, self.reactor.NOW + ) gcmd.respond_info(response) def cmd_disable(self, gcmd): @@ -79,8 +79,9 @@ def cmd_disable(self, gcmd): else: self.is_active = False # Stop extrude factor update timer - self.reactor.update_timer(self.extrude_factor_update_timer, - self.reactor.NEVER) + self.reactor.update_timer( + self.extrude_factor_update_timer, self.reactor.NEVER + ) # Clear filament array self.filament_array = [] # Set extrude multiplier to 100% @@ -90,27 +91,27 @@ def cmd_disable(self, gcmd): def update_filament_array(self, last_epos): self.diameter = self.bdsensor.BD_Sensor_Read(2) - self.gcode.respond_info("Filament width:%.3f" % - (self.diameter)) + self.gcode.respond_info("Filament width:%.3f" % (self.diameter)) # Fill array if len(self.filament_array) > 0: # Get last reading position in array & calculate next # reading position - next_reading_position = (self.filament_array[-1][0] + - self.MEASUREMENT_INTERVAL_MM) + next_reading_position = ( + self.filament_array[-1][0] + self.MEASUREMENT_INTERVAL_MM + ) if next_reading_position <= (last_epos + self.measurement_delay): - self.filament_array.append([last_epos + self.measurement_delay, - self.diameter]) + self.filament_array.append( + [last_epos + self.measurement_delay, self.diameter] + ) if self.is_log: - self.gcode.respond_info("Filament width:%.3f" % - (self.diameter)) + self.gcode.respond_info("Filament width:%.3f" % (self.diameter)) else: # add first item to array - self.filament_array.append([self.measurement_delay + last_epos, - self.diameter]) - self.firstExtruderUpdatePosition = (self.measurement_delay - + last_epos) + self.filament_array.append( + [self.measurement_delay + last_epos, self.diameter] + ) + self.firstExtruderUpdatePosition = self.measurement_delay + last_epos def extrude_factor_update_event(self, eventtime): # Update extrude factor @@ -120,7 +121,8 @@ def extrude_factor_update_event(self, eventtime): self.update_filament_array(last_epos) # Check runout self.runout_helper.note_filament_present( - self.runout_dia_min <= self.diameter <= self.runout_dia_max) + self.runout_dia_min <= self.diameter <= self.runout_dia_max + ) # Does filament exists if self.diameter > 0.5: if len(self.filament_array) > 0: @@ -131,16 +133,18 @@ def extrude_factor_update_event(self, eventtime): item = self.filament_array.pop(0) self.filament_width = item[1] else: - if ((self.use_current_dia_while_delay) - and (self.firstExtruderUpdatePosition - == pending_position)): + if (self.use_current_dia_while_delay) and ( + self.firstExtruderUpdatePosition == pending_position + ): self.filament_width = self.diameter elif self.firstExtruderUpdatePosition == pending_position: self.filament_width = self.nominal_filament_dia - if ((self.filament_width <= self.max_diameter) - and (self.filament_width >= self.min_diameter)): - percentage = round(self.nominal_filament_dia ** 2 - / self.filament_width ** 2 * 100) + if (self.filament_width <= self.max_diameter) and ( + self.filament_width >= self.min_diameter + ): + percentage = round( + self.nominal_filament_dia**2 / self.filament_width**2 * 100 + ) self.gcode.run_script("M221 S" + str(percentage)) else: self.gcode.run_script("M221 S100") From 32b4613f66dafa3ed2519a86c3e651101d9fe5be Mon Sep 17 00:00:00 2001 From: Reubertt Date: Sat, 24 Jan 2026 22:40:58 +0000 Subject: [PATCH 3/3] feat: add axis twist embedded support to BDsensor --- klipper/BDsensor.py | 288 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 287 insertions(+), 1 deletion(-) diff --git a/klipper/BDsensor.py b/klipper/BDsensor.py index 6383555a..1ac1c4c5 100644 --- a/klipper/BDsensor.py +++ b/klipper/BDsensor.py @@ -377,9 +377,47 @@ def scan_sample_event(self, eventtime): pos = self._lookup_toolhead_pos(pos_time) intd = self.mcu_probe.BD_Sensor_Read(0) pos[2] = pos[2] - intd + self.mcu_probe.endstop_bdsensor_offset + + # Axis Twist Manual (Cosine) + atc_obj = self.printer.lookup_object('axis_twist_compensation', None) + twist_applied = 0.0 + + if atc_obj: + try: + def get_cosine_interp(coord, vals, start, end): + if not vals or coord < start or coord > end: return 0.0 + count = len(vals) + if count < 2: return vals[0] + step = (end - start) / (count - 1) + t_raw = (coord - start) / step + idx = int(t_raw) + if idx >= count - 1: return vals[-1] + t = t_raw - idx + mu2 = (1 - math.cos(t * math.pi)) / 2 + return (vals[idx] * (1 - mu2) + vals[idx+1] * mu2) + + # X + if hasattr(atc_obj, 'z_compensations') and atc_obj.z_compensations: + x_start = atc_obj.compensation_start_x if atc_obj.compensation_start_x is not None else atc_obj.calibrate_start_x + x_end = atc_obj.compensation_end_x if atc_obj.compensation_end_x is not None else atc_obj.calibrate_end_x + if x_start is not None and x_end is not None: + twist_applied += get_cosine_interp(pos[0], atc_obj.z_compensations, x_start, x_end) + + # Y + if hasattr(atc_obj, 'zy_compensations') and atc_obj.zy_compensations: + y_start = atc_obj.compensation_start_y if atc_obj.compensation_start_y is not None else atc_obj.calibrate_start_y + y_end = atc_obj.compensation_end_y if atc_obj.compensation_end_y is not None else atc_obj.calibrate_end_y + if y_start is not None and y_end is not None: + twist_applied += get_cosine_interp(pos[1], atc_obj.zy_compensations, y_start, y_end) + + pos[2] += twist_applied + + except Exception: + pass + self.mcu_probe.results.append(pos) # Allow axis_twist_compensation to update results - self.printer.send_event("probe:update_results", pos) + # self.printer.send_event("probe:update_results", pos) # limit the message output to the console else it may take a lot of time if len(self.mcu_probe.results) < 500: self.gcode.respond_info( @@ -764,6 +802,7 @@ def __init__(self, config): ) self.gcode.register_command("BDSENSOR_DISTANCE", self.bd_distance) self.gcode.register_command("BDSENSOR_SET", self.bd_set) + self.gcode.register_command('BDSENSOR_AXIS_TWIST', self.bd_axis_twist_calibrate) self.gcode_move = self.printer.load_object(config, "gcode_move") self.gcode = self.printer.lookup_object("gcode") @@ -1654,6 +1693,253 @@ def get_position_endstop(self): # print("BD get_position_endstop") return self.position_endstop + def bd_axis_twist_calibrate(self, gcmd): + import math # Ensures import for square root + + axis_param = gcmd.get('AXIS', 'BOTH').upper() + + # If DEGREE is specified, force that degree. + # Otherwise (default 0), activate AUTO mode. + force_degree = gcmd.get_int('DEGREE', 0) + + axes_to_scan = [] + if axis_param == 'BOTH': axes_to_scan = ['X', 'Y'] + elif axis_param == 'X': axes_to_scan = ['X'] + elif axis_param == 'Y': axes_to_scan = ['Y'] + else: + self.gcode.respond_info("Error: Invalid axis.") + return + + mode_str = "AUTO-TUNE" if force_degree == 0 else "FORCED (Degree %d)" % force_degree + self.gcode.respond_info("--- Axis Twist: Scan + Math (%s) ---" % mode_str) + + self.is_axis_twist_active = True + toolhead = self.printer.lookup_object('toolhead') + + # Limits (Same safe logic as before) + scan_min_x, scan_max_x = 20.0, 200.0 + scan_min_y, scan_max_y = 20.0, 200.0 + try: + curtime = self.printer.get_reactor().monotonic() + status = toolhead.get_status(curtime) + phys_min_x, phys_max_x = float(status['axis_minimum'][0]), float(status['axis_maximum'][0]) + phys_min_y, phys_max_y = float(status['axis_minimum'][1]), float(status['axis_maximum'][1]) + bed_mesh = self.printer.lookup_object('bed_mesh', None) + if bed_mesh: + # Try to get mesh configs + if hasattr(bed_mesh, 'bmc'): cfg = bed_mesh.bmc + elif hasattr(bed_mesh, 'mesh_min'): cfg = bed_mesh + else: cfg = None + + if cfg: + scan_min_x, scan_max_x = float(cfg.mesh_min[0]), float(cfg.mesh_max[0]) + scan_min_y, scan_max_y = float(cfg.mesh_min[1]), float(cfg.mesh_max[1]) + except: pass + + center_x = (scan_max_x - scan_min_x) / 2.0 + scan_min_x + center_y = (scan_max_y - scan_min_y) / 2.0 + scan_min_y + + # Increased points to 20 for Auto-Tune to work well + points = gcmd.get_int('POINTS', 20) + z_hop = gcmd.get_float('Z_HOP', 5.0) + + old_col_homing = self.collision_homing + old_col_cal = self.collision_calibrate + self.collision_homing = 1 + self.collision_calibrate = 0 + + if 'z' not in toolhead.get_status(curtime)['homed_axes']: + self.gcode.run_script_from_command("G28") + + try: + self.gcode.run_script_from_command("SET_GCODE_VARIABLE MACRO=_HACK_SAFE_Z VARIABLE=allow_unsafe_z VALUE=True") + except: pass + + final_results = {} + + # --- EXECUTION OF SCAN --- + for current_axis in axes_to_scan: + self.gcode.respond_info(">>> Scan Axis %s (%d points)..." % (current_axis, points)) + + # Geometry + if current_axis == 'X': + start_val, end_val = scan_min_x, scan_max_x + fixed_pos = center_y + if start_val < phys_min_x + 5: start_val = phys_min_x + 5 + if end_val > phys_max_x - 5: end_val = phys_max_x - 5 + else: + start_val, end_val = scan_min_y, scan_max_y + fixed_pos = center_x + if start_val < phys_min_y + 5: start_val = phys_min_y + 5 + if end_val > phys_max_y - 5: end_val = phys_max_y - 5 + + step = (end_val - start_val) / (points - 1) + axis_data_points = [] + + for i in range(points): + current_pos_val = start_val + (i * step) + if current_axis == 'X': target = [current_pos_val, fixed_pos, z_hop] + else: target = [fixed_pos, current_pos_val, z_hop] + + self.toolhead.manual_move(target, 100.0) + self.toolhead.wait_moves() + self.gcode.run_script_from_command("G28 Z") + time.sleep(0.1) + + val = self.bd_value + axis_data_points.append([current_pos_val, val]) + self.gcode.respond_info(" Pt %d: Pos=%.1f | Z=%.4f" % (i+1, current_pos_val, val)) + self.toolhead.manual_move([None, None, z_hop], 100.0) + + final_results[current_axis] = { 'raw_data': axis_data_points, 'start': start_val, 'end': end_val, 'fixed': fixed_pos } + + # --- CLEANUP --- + self.collision_homing = old_col_homing + self.collision_calibrate = old_col_cal + self.is_axis_twist_active = False + try: + self.gcode.run_script_from_command("SET_GCODE_VARIABLE MACRO=_HACK_SAFE_Z VARIABLE=allow_unsafe_z VALUE=False") + except: pass + self.gcode.run_script_from_command("G28 Z") + + # --- MATH ENGINE --- + def polynomial_regression(data_pairs, degree): + n = len(data_pairs) + if n < degree + 1: return [0.0] * (degree + 1) + X = [p[0] for p in data_pairs] + Y = [p[1] for p in data_pairs] + sigma_x = [0.0] * (2 * degree + 1) + for i in range(2 * degree + 1): sigma_x[i] = sum([x**i for x in X]) + sigma_xy = [0.0] * (degree + 1) + for i in range(degree + 1): sigma_xy[i] = sum([Y[j] * (X[j]**i) for j in range(n)]) + matrix_A = [] + for i in range(degree + 1): + row = [] + for j in range(degree + 1): row.append(sigma_x[i + j]) + matrix_A.append(row) + N = len(matrix_A) + for i in range(N): + pivot = matrix_A[i][i] + for j in range(i + 1, N): + factor = matrix_A[j][i] / pivot + for k in range(i, N): matrix_A[j][k] -= factor * matrix_A[i][k] + sigma_xy[j] -= factor * sigma_xy[i] + coeffs = [0.0] * N + for i in range(N - 1, -1, -1): + sum_ax = sum([matrix_A[i][j] * coeffs[j] for j in range(i + 1, N)]) + coeffs[i] = (sigma_xy[i] - sum_ax) / matrix_A[i][i] + return coeffs + + def eval_poly(coeffs, x): + y = 0.0 + for i, c in enumerate(coeffs): y += c * (x**i) + return y + + # --- AUTO-SELECTION LOGIC (CALIBRATED AI) --- + # --- RANGE OPTIMIZATION LOGIC (BED FLATNESS) --- + def find_best_fit(pairs, max_degree=4): + best_deg = 1 + best_range = 9999.0 + best_coeffs = [] + + # Get the original range (without compensation) to compare + z_vals_raw = [p[1] for p in pairs] + raw_range = max(z_vals_raw) - min(z_vals_raw) + + # Test each degree + for d in range(1, max_degree + 1): + coeffs = polynomial_regression(pairs, d) + + # Simulate the residual (what remains after correction) + residuals = [] + for p in pairs: + prediction = eval_poly(coeffs, p[0]) + # The residual is the error the compensation couldn't remove + residuals.append(p[1] - prediction) + + # Calculate the Range of the residual (Peak to Peak) + current_range = max(residuals) - min(residuals) + + # --- DECISION CRITERIA --- + # 1. Penalty of 0.005mm (5 microns) per extra degree. + # Only increase degree if range improvement is greater than 5 microns. + # This prevents overfitting due to sensor noise. + effective_range = current_range + (d * 0.005) + + if d == 1: + best_range_score = effective_range + best_deg = d + best_coeffs = coeffs + final_real_range = current_range + else: + if effective_range < best_range_score: + best_range_score = effective_range + best_deg = d + best_coeffs = coeffs + final_real_range = current_range + + return best_deg, best_coeffs, final_real_range + + # --- PROCESSING AND OUTPUT --- + configfile = self.printer.lookup_object('configfile') + section_name = 'axis_twist_compensation' + + out = [] + out.append("") + out.append("-" * 20) + out.append("FINAL RESULT (AUTO-TUNE):") + out.append("[axis_twist_compensation]") + + for axis_key in final_results: + pack = final_results[axis_key] + pairs = pack['raw_data'] + + try: + # DEGREE SELECTION + if force_degree > 0: + deg = force_degree + coeffs = polynomial_regression(pairs, deg) + rmse = 0.0 # irrelevant + else: + deg, coeffs, rmse = find_best_fit(pairs) + self.gcode.respond_info("Axis %s: Best fit found -> Degree %d (Mean Error: %.5fmm)" % (axis_key, deg, rmse)) + + # GENERATE SMOOTH CURVE + fitted_values = [] + for p in pairs: + fitted_values.append(eval_poly(coeffs, p[0])) + + avg = sum(fitted_values) / len(fitted_values) + comps_str = ", ".join(["%.6f" % (avg - v) for v in fitted_values]) + + # Save + if axis_key == 'X': + configfile.set(section_name, 'calibrate_start_x', "%.1f" % pack['start']) + configfile.set(section_name, 'calibrate_end_x', "%.1f" % pack['end']) + configfile.set(section_name, 'calibrate_y', "%.1f" % pack['fixed']) + configfile.set(section_name, 'z_compensations', comps_str) + out.append("# --- AXIS X (Auto Degree %d) ---" % deg) + out.append("calibrate_start_x: %.1f" % pack['start']) + out.append("calibrate_end_x: %.1f" % pack['end']) + out.append("calibrate_y: %.1f" % pack['fixed']) + out.append("z_compensations: %s" % comps_str) + else: + configfile.set(section_name, 'calibrate_start_y', "%.1f" % pack['start']) + configfile.set(section_name, 'calibrate_end_y', "%.1f" % pack['end']) + configfile.set(section_name, 'calibrate_x', "%.1f" % pack['fixed']) + configfile.set(section_name, 'zy_compensations', comps_str) + out.append("# --- AXIS Y (Auto Degree %d) ---" % deg) + out.append("calibrate_start_y: %.1f" % pack['start']) + out.append("calibrate_end_y: %.1f" % pack['end']) + out.append("calibrate_x: %.1f" % pack['fixed']) + out.append("zy_compensations: %s" % comps_str) + except Exception as e: + self.gcode.respond_info("Error calculating %s: %s" % (axis_key, str(e))) + + out.append("-" * 20) + self.gcode.respond_raw("\n".join(out)) + self.gcode.respond_info("SUCCESS: Type SAVE_CONFIG.") + def load_config(config): bdl = BDsensorEndstopWrapper(config)