Strain Gauge/Load Cell based Endstops

Thank you for your answer !
I now have an ADS1220 and configuring LOAD_CELL is OK.
image

However, configuring load_cell_probe will cause an error.

Can you help me see what the problem is?
Here is my configuration.

[load_cell_probe]
sensor_type: ADS1220
cs_pin: PC15
#   The pin connected to the ADS1220 chip select line. This parameter must
#   be provided.
spi_speed: 512000
#   This chip supports 2 speeds: 256000 or 512000. The faster speed is only
#   enabled when one of the Turbo sample rates is used. The correct spi_speed
#   is selected based on the sample rate. 
#spi_bus:2
spi_software_sclk_pin: PB13
spi_software_mosi_pin: PC2
spi_software_miso_pin: PC3
#   See the "common SPI settings" section for a description of the
#   above parameters.
data_ready_pin: PC13
#   Pin connected to the ADS1220 data ready line. This parameter must be
#   provided.
gain: 128
#   Valid gain values are 128, 64, 32, 16, 8, 4, 2, 1
#   The default is 128
sample_rate: 660
#   This chip supports two ranges of sample rates, Normal and Turbo. In turbo
#   mode the chips c internal clock runs twice as fast and the SPI communication
#   speed is also doubled. 
#   Normal sample rates: 20, 45, 90, 175, 330, 600, 1000
#   Turbo sample rates: 40, 90, 180, 350, 660, 1200, 2000
#   The default is `660`
counts_per_gram: 131.755777
reference_tare_counts: 537140
#counts_per_gram = 131.35294
#reference_tare_counts = 557651
safety_limit: 1000.0
#   The safe limit for probing force relative to the reference_tare_counts on
#   the load_cell. The default is +/-1Kg.
trigger_force: 200.0
#   The force that the probe will trigger at. 50g is the default.
continuous_tare_highpass: 0.8
#   Enable optional continuous taring while homing & probing to reject drift.
#   The value is a frequency, in Hz, below which drift will be ignored.This
#   option requires the SciPy library. Default: None
continuous_tare_lowpass: 39
#   The value is a frequency, in Hz, above which high frequency noise in the
#   load cell will be igfiltered outnored. If this option is set,
#   continuous_tare_highpass must also be set. Default: None
continuous_tare_notch: 30, 25
#   1 or 2 frequencies, in Hz, to filter out of the load cell data. This is
#   intended to reject power line noise. If this option is set,
#   continuous_tare_highpass must also be set. Default: None
#continuous_tare_notch_quality: 2.0
#   Controls how narrow the range of frequencies are that the notch filter
#   removes. Larger numbers produce a narrower filter. Minimum value is 0.5 and
#   maximum is 3.0. Default: 2.0
continuous_tare_trigger_force: 100
#   The force that the probe will trigger at whe using the continuous tearing
#   filter. 40g is the default.
#tap_filter_notch: 60.0
#tap_filter_notch_quality: 2.0
#   Filters the load cell data before the tap is evaluated. This option may
#   provide marginal accuracy improvement when notch filtering at the mains
#   power frequency. Requires SciPy. Default: None
#trigger_count: 1
#   The number of samples over the trigger_force_grams threshold that will cause
#   the probe to trigger. 1 is the default.
#pullback_dist: 0.1
#   The distance of the pullback move in mm. This move needs to be long enough
#   to bring the probe away from the bed after it makes contact.
#pullback_speed: 0.4
#   Speed of the pullback move. The default value is to move at a speed of 1
#   sample every 1 micron based one the sensors sample rate is.
settling_time: 0.375
#   Additional time to wait before taring the probe. This allows any vibrations
#   to settle and bowden tubes time to flex etc. This improves repeatability.
#   If the continuous_tare_filter is used this may be set to 0.
#pullback_extra_time: 0.3
#   Time to collect additional samples after the pullback move ends in seconds.
#   This improves accuracy by giving the algorithm more points after the probe
#   breaks contact with the bed. Disabling this entirely may impact reliability.
#tare_count: 16
#   The number of samples to use when automatically taring the load_cell before
#   each probe. The default value is: sample_per_second * (1 / 60) * 4. This
#   collects samples from 4 cycles of 60Hz mains power to cancel power line
#   noise.
#bad_tap_module:
#   Name of a printer object that implements the BadTapModule interface. This
#   checks taps to see if they meet minimum requirements and can
#nozzle_cleaner_module:
#   Name of a printer object that implements the NozzleCleanerModule interface
#   than can handle nozzle cleaning. If one is provided the nozzle_cleaner_gcode
#   is disabled.
#nozzle_cleaner_gcode:
#   A Gcode macro that is called when a bad tap is detected and the nozzle needs
#   to be cleaned. The default Gcode prints a warning to the console.
z_offset: 0
speed: 2
samples: 3
sample_retract_dist: 2
lift_speed: 2
samples_result: median
#samples_tolerance:
#samples_tolerance_retries:
#activate_gcode:

Interesting!
In fact we are currently discussing a ADS1220 board for further testing. Where / how did you get this board with the ADS1220.

It would be great to share some details on your setup.

I bought the ADS1220 board on Taobao.ADS1220
Do you know how I can configure load_cell_probe to make ADS1220 work properly? This is the real-time sensor data from when I moved manually.

I have a board similar to what @gengge has.

Iā€™m trying to configure it on a delta with 3 load cells on the bed. I had an hx711 connected to an arduino nano before and I was able to get about 15um deviation with it when probing really slow. Itā€™s a bit temperamental though and the code quite complicated. Of course thereā€™s the problem of the bed heating.

I tried quickly today with the ADS1220 but couldnā€™t make it work. Can someone confirm what is the latest code I should try? Thanks

I think the branch linked in this thread doesnā€™t have the ADS1220 support enabled for the load cell. I have another set of branches that Iā€™m preparing for submission to klipper, as Kevin requested that I break up the changes into digestible chunks. They are more up-to-date but the tip of the stack is missing the nozzle thermal expansion stuff.

I am super-busy with trying to get the ADS1220 board produced for Reno Vice. Iā€™m trying to get the order placed for the first prototype board today (:crossed_fingers:).

sneak peak?

But that means its going to be maybe a week before I get a chance to rebase onto klipper mainline, add the thermal expansion stuff and give you a good branch to test the ADS1220.

well if thereā€™s anything I can do to helpā€¦ testing or otherwise

I bought HX717 and configured load_cell_probe to make it work. But I had problems with it. I wrote a Gcode file to call probe multiple times.
After multiple attempts, the PROBE will report an error "Internal error on command:ā€œPROBEā€ ".
This is the error in my klippy.log

BatchBulkHelper batch callback error
Traceback (most recent call last):
  File "/home/pi/klipper/klippy/mcu.py", line 71, in _do_send
    return xh.get_response(cmds, self._cmd_queue, minclock, reqclock)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/klipper/klippy/serialhdl.py", line 326, in get_response
    raise error("Unable to obtain '%s' response" % (self.name,))
serialhdl.error: Unable to obtain 'sensor_bulk_status' response

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/klipper/klippy/extras/bulk_sensor.py", line 72, in _proc_batch
    msg = self.batch_cb(eventtime)
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/klipper/klippy/extras/hx71x.py", line 151, in _process_batch
    self.clock_updater.update_clock()
  File "/home/pi/klipper/klippy/extras/bulk_sensor.py", line 233, in update_clock
    params = self.query_status_cmd.send([self.oid])
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/klipper/klippy/mcu.py", line 75, in send
    return self._do_send([self._cmd.encode(data)], minclock, reqclock)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/pi/klipper/klippy/mcu.py", line 73, in _do_send
    raise self._error(str(e))
gcode.CommandError: Unable to obtain 'sensor_bulk_status' response
1 Like

So there was an error somewhere ā€œupā€ in the config file from there thatā€™s the root cause. Can you DM me the whole log file?

(Gory Details: The way that klipper shuts down on error, it halts the MCU and terminates the serial I/O. This in turn causes any outstanding serial I/O task to fail and throw exceptions which also get logged. But unfortunately this happens after the real error that kicked off the shutdown is logged, usually at least 200 log lines after, because klipper logs the last 100 messages sent and received on every serial bus (for every mcu) first.)

Okay, hereā€™s my log file. Thanks.
klippy (0).log (107.9 KB)

1 Like

I changed the code. Comment this and it wonā€™t report any errors.
#self.tap_r_squared = self.calculate_r_squared()

did you find a board for the HX717 or you built your own PCB?

I used the previous HX711 board and replaced the chip with an HX717. Pins S0 and S1 need to be pulled high.

Looks like an off by 1 error:

"/home/pi/klipper/klippy/extras/load_cell_probe.py", line 246, in segment_variance
    load = force[i]
           ~~~~~^^^
IndexError: index 1049 is out of bounds for axis 0 with size 1049

Strange that Iā€™ve never run into this??

That plot doesnā€™t depict a valid tap. It looks like itā€™s cut off? I donā€™t see the pullback move?

Iā€™m not familiar with this area. Thank you for your answer.

I want to use the load cell value in gcode_macro. Like ā€œprinter. Extruder. Temperatureā€ .So, what should I do to get this value?

you can get force_g from the load cell object. docs

The following information is available for each [load_cell name]:

'is_calibrated': True/False is the load_cell calibrated
'counts_per_gram': The number of raw sensor counts that equals 1 gram of force
'reference_tare_counts': The reference number of raw sensor counts for 0 force
'tare_counts': The current number of raw sensor counts for 0 force
'force_g': The force in grams, averaged over the last polling period.
'min_force_g': The minimum force in grams, over the last polling period.
'max_force_g': The maximum force in grams, over the last polling period.
'std_force': The standard deviation of the force in grams, over the last polling period

Ok,thanks!

@garethky

Hi,

I reached out after having some discussions with Ella Fox. Iā€™m working on a load cell-based ā€œprobeā€ as well, but my design involves a setup with four sensors mounted on the four corners of the bed.

My sensor consists of a standard 1.6mm PCB with large SMD resistors mounted on it. When the PCB bends, the resistors also bend, causing a change in resistance.

It will take me some more time to finish the amplifier and MCU board, but Iā€™ll be sure to share the data once itā€™s ready.

3 Likes

Important Update on Branches

(I know Iā€™ve made a lot of them)

To successfully merge all the code into klipper mainline I have to break the code up in digestible chunks for @koconnor to review. As part of that plan we have outlined at least 4 more PRs. Iā€™ve adopted a new tool, jj, to make this easier to manage. One of jjā€™s strengths is managing ā€œcommit stacksā€ which are chains of branches that all depend on each other. This lets me run and test the printer as if all the code is merged but with just 1 PR under review.

Iā€™ve created a new branch which is a maker of where you can test the code. But be aware, this commit stack is going to be under active development. We plan to make changes to the config and there will be breaking changes. Primarily Iā€™ve been asked to merge [load_cell] and [load_cell_probe]. But there may be changes to the meaning or naming of some config options. If you are going to use this branch it would be best to follow along with the current open PR as this branch will change at the same time as the active PR does.

The load-cell-probe-community-testing branch has the main readme.md file edited to link to all of the load cell probing documentation and tooling. So now there is one place to find everything.

The old branch, adc-endstop, will remain as a historical reference.

For this curious, this is what PR stack looks like in the jj visual client gg:

Things will be submitted from the bottom of the screenshot to the top. The readme.md will be updated with links to the PRā€™s as they get submitted so its easy to follow along.

1 Like

Hi. what about K1 - this not usebale for K1? Iā€™m trying and all working good but after some gcode - printer go to shutdown with errors -

type or paste code herejson encoding error: Object of type bool_ is not JSON serializable
Traceback (most recent call last):
  File "/usr/data/klipper/klippy/webhooks.py", line 272, in send
    jmsg = json.dumps(data, separators=(',', ':'))
  File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
    return cls(
  File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type bool_ is not JSON serializable
Transition to shutdown state: json encoding error: Object of type bool_ is not JSON serializable

And this 100% repeatable - run bed_mesh_calibration, run smart_park and after set extruder temp to 245 - and after 5-7 sec printer show this error and shutdown.