Strain Gauge/Load Cell based Endstops

Looks like it could work. 24bits, PGA with gain up to 128. Seems like the max sample rate sacrifices noise bits, but the 640Hz rate would be great!

It’s SPI but the SPI data out pin is also the “data ready” pin. With the Klipper internals you probably have to plug that pin into 2 pins on the MCU so you can check DRDY efficiently.

Spec sheet: http://www.asidesigner.com/Files/PartFiles/15315/222/cs1237_datasheet.pdf

Is this link the code you shared related to weigh detection? How do I need to verify or modify the configuration what with CS1237
https://github.com/RF1000community/klipper/blob/master/klippy/extras/load_cell_probe.py

That actually isn’t my code.

My branch/repo uses c to read the sensor as it can be connected to an endstop without having to transmit the data back to the Pi to detect a collision. Each chip needs its own c driver like this: https://github.com/garethky/klipper/blob/adc-endstop/src/sensor_ads1263.c

OK, thanks, by the way the current one you submitted implements z-axis detection? Is there any other functionality attached to it? Detecting plugging or extrusion pressure?

I’m focused on robust probing, but the infrastructure is there for continuous monitoring of the data. E.g. I already have the data being broadcast over web socket to a front end. Other modules will be able to consume this data stream for things like clog detection.

OK understood. Thank you for sharing the process and results

Is the switching of the loadcell with a tool change something thats easy to implement software side? Or is it easier to try under-bed loadcells? Still trying to figure out how to implement this on my toolchanger build

This will be a kind of PRobe, so anything you can do with a probe you can do with this. And anything you cant do, you wont be able to do with this either.

Probe is currently limited to 1 instance. It’s Gcode commands don’t allow you to specify one of n probes like, for example, extruders do. If they did you could have as many probes as you like and use one with each extruder. Someone needs to fix Probe so it can be multiple Probes.

From what I gathered from @leadinglights research on in-bed loadcells, the results are not as promising as in-toolhead sensors. Because the force is applied, essentially, to a system of levers it varies in strength over the bed surface. There are “dead spots” where some of the force lifts one of the load cells canceling out downward force on another sensor. He had a super nice plot of a bed surface scan over on reprap.org that I just cannot find right now.

1 Like

This one?

1 Like

Thats the one!

There be Dragons!

So, to sum it up, either way sucks :joy:

I have looked through the code but it has been a while since i had to use python. If I get this right these command registrations limit the use of multiple probes:

        self.gcode.register_command('QUERY_PROBE', self.cmd_QUERY_PROBE,
                                    desc=self.cmd_QUERY_PROBE_help)

So a good approach would be to compare the extruder class with the probe class?
Also I thought about using this extension: https://github.com/TypQxQ/Klipper_ToolChanger - I guess I would have too take care that this extension also is able to support multiple probes, because i have to assign them somehow.

Regarding bed sensors: That’s quite interesting but it’s using piezoelectric discs and I’m not convinced you have the same problems with load cells. I mean, in general it is possible with piezoelectric discs because the bambulab x1 does it - but maybe they compensated somehow or they just measure at certain points. Piezoelectric discs are only able to sense motion so its necessary to be a dynamic event with a certain speed while loadcells measure a force - so you are able to slow down the process and measure more static, eliminating dynamic effects.

Maybe I will just do both, a bed and tool sensor, on the hardware side so that I’m able to test both of it.

A few points:

Piezoelectric discs are only able to sense motion so it’s necessary to be a dynamic event

A piezoelectric sensor can behave very much like a strain gauge as long as the time is short enough. With contact sensing, this is the case as the time from nozzle contact to a sensible pressure (3 to 10 grams) is in the milliseconds. For extrusion sensing, on the other hand, the fit is very poor as the measurement is continuous and a better accuracy is needed than in a contact event.

I have not come across any really elegant way of fitting piezo sensors into the print head. I have tried something similar to the way the strain gauges are used in the Duet3D smart effector, but the results were not encouraging.

Maybe I will just do both, a bed and tool sensor, on the hardware side so that I’m able to test both of it.

A two-tool option with a bed and a tool sensor is to use a single strain gauge mounted on a bed mounting. Probing with the nozzle would be done directly over this to get the Z datum. Bed mesh could be done with any other sensor (e.g., BLTouch) This is similar to what I am using at the moment with some success.

I got my Prusa XL:

There is a lot of negative press about this printer and I’m seeing some of the things people are complaining about. E.g. there are layer shifts are in this print. But the load cell probing is a bright spot. It just works. The fully automatic routines for aligning the docks and tool-to-tool offset measurement are amazing and so much better than what E3D had for their tool changer.

My goal when I started this work was to buy the XL and klipper-ize it.

But we have a ways to go:

  • Hardware support for all of Prusa’s custom boards, which they haven’t released info on yet.
  • CANBUS for the tool boards (at least I think its CANBUS, I cant find the canbus chip on the tool board!)
  • Support loadcells
  • Support multiple probes
  • Support using a probe in the X and Y directions, not just z (Homing and pretty much everything else assumes it only Z)
  • Tool-to-tool offset measurement routine

Honestly, its a LOT to tackle as a part time hobby. I may never get there.

2 Likes

Fabulous stuff! I’ve been noodling on hardware for this for some time now, and helping folks over on Armchair Engineering who are continuing the work as well. Looking forward to seeing more progress and helping where I can!

1 Like

Hello! I tried to install your implementation of load_cell_endstop on Creality K1. The scale board on it is a GD32E230F8 and 4 pieces of HX711. Reading from all cells works, but the limit switch functionality does not work. The logger throws ERROR_SCHEDULE and sometimes ERROR_SAMPLE_NOT_READY errors. Diagnostics shows no errors.

The stock script from Creality gave an SD of around 0.005, but it is closed source and does not work on a pure Klipper.

The entire Creality K1 community is looking forward to your implementation of the limit switch on 4 cells simultaneously! We will be happy to help in any way we can.

1 Like

I was not aware that they did this in the K1. Using 4 chips is the right approach though. The current implementation I have can only trigger from 1 load cell in an endstop. Using 4 is not currently possible.

The triggering is based on a tare value and any deviation (either + or -) from that value greater than a threshold. That approach has been rock solid in testing. “The Right Thing To Do” for 4 sensor is to fuse their readings in the endstop such that you are looking at the total deviation on all 4:

deviation = abs(sensor1_reading - sensor1_tare) + 
            abs(sensor2_reading - sensor2_tare) +
            abs(sensor3_reading - sensor3_tare) + 
            abs(sensor2_reading - sensor2_tare)
if (deviation >= threashold) {
    // trigger trsync...
}

This gets around the problems with one end of the bed lifting up, canceling out the downward force on the other end. It also avoids integer overflows.

But it requires reading all 4 sensors and delivering their data to 1 endstop and I don’t currently have that solved. I’ll have to think about that one… I wouldn’t tackle it without some hardware on hand to actually try it out with. (Anyone in the Seattle area with a K1 they want to sacrifice to the alter of open source?)

Ive seen the same in my testing. ERROR_SAMPLE_NOT_READY is something I have been working on. It seems these chips (HX71x family) sometimes don’t have a sample ready even through enough clock cycles have passed. I’m considering fixing this with “aggressive” retry logic if this happens. ERROR_SCHEDULE is something I have not seen. What I have done is decouple the endstop from the errors in the chip code by using a separate watchdog timer in the endstop. If the watchdog wakes up and there hasn’t been a sample delivered recently it triggers the endstop. This gives us safety and loose coupling.

Hehe :sweat_smile: no pressure.

1 Like

Currently the K1/max Does have some *.c files for the hx711 that read all 4 sensors at least it seems to loop through the GPIO assigned to them on the GD32 SOC

There is a small group of us chasing “real” klipper on this machine instead of “creality OS”
Let us know how we can contribute. Do you accept PR’s against your current branch of klipper? What would be preferred ettiquette for that?

If you need HW to test with SUPPOSEDLY creality is sending me another bed PCB (they treat them like guarded national secrets…) if they do indeed send me a spare PCB and not just the hotbed itself I would be willing to ship this out to you in order to help with developement

1 Like

Thats totally whats goin on there, its reading all 4 sensors and then sending them all back to the Pi in 1 packet. Interestingly they are sampling at 2x the actual chip sample rate, I assume to deal with the chip not being ready.

The klippy code is suspiciously missing. My guess is the magic is in these binary files they have compiled with c python: https://github.com/CrealityOfficial/K1_Series_Klipper/blob/2a4ee4128299dc38f5dd49edec3b63f6b440e0a3/klippy/extras/prtouch_v1_wrapper.cpython-38-mipsel-linux-gnu.so
Thats ummmm, very much not open source.

This python file configures the custom Probe object from those binaries: https://github.com/CrealityOfficial/K1_Series_Klipper/blob/2a4ee4128299dc38f5dd49edec3b63f6b440e0a3/klippy/extras/prtouch_v2.py

This approach is what I set out to avoid. Sending the data back to the MCU is slower than evaluating it on the MCU. Doing it on the MCU saves a whole round trip when trying to stop the steppers. But it is conceptually easier to implement and keeps your c code simpler.

I don’t really know… I’d like to get a demo working of 1 sensor in 1 toolhead that can print. Once I get there I think we can go back and look at this multi-sensor idea. Its easier to adapt something thats working vs hacking on something that is currently broken.

I’ve got 4 weekends left in the year where I will have free time to work on this, lets see what I can get done and then sync up in January?

1 Like

OK I will be willing to setup a single load cell as an endstop for my Z or similar on another printer for testing as well :wink: I could probably mock this up on my trident

Some of their older python before they moved to the cpython strategy

Currently using the prtouch.py and hx711s.py with success in my k1 on a manta m5p running klipper but the mesh is unreliable and sometimes has spikes

1 Like

Wow they wrote a pile of code! Their python… I’m not reading 2000 lines of undocumented python like that. Its good feedback to know that its not reliable, we still have value to add here.

I see potential problems with what they did in C at least. There is no good reason for the 4 sensors to stay in sync, unless the board has the same external clock source hooked up to all of the HX711 chips. If they don’t, each chip’s internal clock should slowly drift away from the others. Some macro shots of the board could help there. If they used a single clock their C code looks less naive.

It looks like their polling frequency math is:

REST_TICKS = (120000000 / 10000 * 125) / 2 = 750,000

Dividing the clock speed in ticks per second by the rest ticks gives (120000000 / 750,000) = 80. So they sleep for exactly the sample period which is 1/80th of a second.

This is the last CPU intensive thing you can do, but also the least accurate. My understanding of theses Delta Sigma ADC devices is that they take the sample period to prepare a sample, then the sample is copied into a register and the ‘data ready’ pin it set. That sample sits in the register for the next entire sample period getting stale. So when you read the sample like this its inevitable that you have an uncertainty about exactly how stale it has become. Its something between 0 and sample period. That depends on the sensor and CPU clocks and blind luck. The printer moves some amount during this time… which we have no way to account for.

In the code I’ve been testing I got around this problem by brute force. I just turned the sample rate up to 40Khz. That brings that uncertainty down to 1/40,000 of a second. IT also totally gets rid of ERROR_SAMPLE_NOT_READY. This works well but adds a load of wasted CPU overhead.

I am going to prototype using a sliding window strategy to optimize the high frequency polling. I think I can get a 95% CPU usage improvement with no loss in resolution. But probably after I get a release out that just prints.

1 Like