-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add filament_motion_sensor #3857
Conversation
Add functionality to support a Filament Motion Sensor for detecting extruder jams as well as runouts. Works by an encoder toggling the switch_pin 0/1 as the filament is pulled through the sensor.
Addresses Issue Filament jam sensor Klipper3d#1327 Signed-off-by: Joshua Wherrett thejoshw.code@gmail.com
Does it make sense to add some sort of calibration. E.g.:
E.g. https://www.aliexpress.com/item/4000269547406.html?spm=a2g0s.9042311.0.0.4bc64c4d272cF6
So the returned value needs to end up somewhere between 43,363 mm and 50 mm. Or rather vice versa: Extrude until, e.g 8 slots have passed the sensor and return the extruded length? |
@Sineos yep calibration is next when I have time. |
Resolves: #3715 |
The changes to pause_resume.py are not correct. It should not command Octoprint to pause or resume the print as it has already happened. The |
@Arksine I'll respond to your comment first, then go into more detail as to my understanding of how pause/resume works (happy to be corrected at any point). According to the OctoPrint docs (https://docs.octoprint.org/en/master/features/action_commands.html), action:pause and action:paused do almost the same thing, however action:paused prevents OctoPrint from running any GCODE, which is not what we want as you will see below. As for the details, pause/resume is an asynchronous event that can be commanded from many places such as the Klippy "firmware" as we are using it here, but it can also be commanded from OctoPrint using pause/resume buttons and from the Printer LCD using the OctoPrint menu. By default, OctoPrint and the Printer LCD do the equivalent of sending action:pause(d) to OctoPrint which tells OctoPrint to stop queueing GCODE. The printer will continue to print any already queued GCODE, plus there is not feedback to the printer that a pause event has occurred, and the filament_motion_sensor plugin needs to know if the printer has been paused for event handling. So the first task was to enable the pause/resume feedback by ensure the PAUSE and RESUME GCODE provided by the pause_resume plugin is called in all cases. I explain how to do this in Klipper docs FilamentMotionSensor.md. This has the bonus of being able to use the pause SD card print functionality provided by pause_resume from all these places too, which in my opinion is a more complete and consistent pause/resume implementation. The other issue is the asynchronous nature of pause/resume. Once a pause is issued, OctoPrint stops sending GCODE to Klipper, however Klipper likely has a number of GCODEs already queued, and remember pause simply stops the flow of GCODE from OctoPrint, Klipper doesn't actually respond in anyway to the action:pause(d) command. Klipper will continue to print any queued moves, which could take a while (seconds) from when the pause was issued, especially if there are long extruder moves queued for a large print with long straight edges. Klipper can also be moved after a pause is issued, using the Printer LCD or a PARK GCODE macro so filament can be changed, etc. The pause_delay goes someway to address this by allowing the user to configure some arbitrary time between when the action:pause(d) command is issued and the printer actually stopping printing, to roughly ensure the runout_gcode is executed after OctoPrint has stopped sending GCODE (you do not want OctoPrint sending GCODE after Klipper thinks it has paused as these GCODE will get combined with the runout_gcode and SAVE_GCODE_STATE will save the incomplete state). So in summary, there are a number of things we could do to pause_resume to make it more robust, like flushing moves, or checking idle timeout for printer being in idle, so we can be more deterministic about the gap between commanding a pause to the host using action:pause(d) and the host actually pausing the GCODE, to Klipper flushing all those moves to the printer and the printer completing the moves. |
Initially the
There should be at most one queued gcode when a runout is detected. The The
What you are dealing with here is not queued gcode, its queued moves in the lookahead buffer. This makes "tracking" sensors a challenge, as you are comparing real-time feedback of the encoder against a future position. It does seem that you are estimating the extruder's current position which is desirable for a sensor like this.
It might not be a bad idea for the filament sensor to replace the |
@Arksine thanks for the clarification, happy to revert the changes to pause_resume.py. I mainly made them to maintain consistency between pauses commanded via pause_resume.py and those commanded via the printer LCD OctoPrint Pause menu item (which calls action:pause/resume directly), so maybe menu.cfg needs to be changed to action:paused/resumed too. Take a look at FilamentMotionSensor.md and see if the extra changes changes I recommend at the bottom make sense. One issue I came across, was that filament_motion_sensor.py was calling send_pause_command() then waiting pause_delay then running PAUSE GCODE followed by runout_gcode and M400 (as you mentioned) this all worked fine. As an example when this happens on a runout, I go to the printer, replace the filament and select OctoPrint -> Resume on the printer LCD, by default this only triggers action:resume which causes OctoPrint to start sending GCODE to Klipper again. The issue with this is that RESTORE_GCODE_STATE is not called to restore printer state, nor is is_paused and pause_command_sent cleared as would be done if RESTORE GCODE was called. So I recommended changes that makes this all consistent and ensure PAUSE, RESUME and CANCEL_PRINT GCODE is called in all situations. |
I agree that the behavior should be consistent in Klipper. Ideally the Octoprint menu would call PAUSE and RESUME if |
@Arksine no worries. pause_resume.py defines the PAUSE gcode command which calls action:pause(d) so that should work as is. Just need a consistent way to call it. |
can you please add so the amount between the pulses are in the config? so custom types are possible? Thank you. |
Are you referring to the length of filament? because i do see this setting: |
Ohh yes i totaly missed that. Thank you! |
Ive been testing this and so far so good. Although i notice it sends a |
Thanks all for testing this. Whenever the extruder moves the filament_motion_sensor plugin will be measuring the length extruded and will trigger if the sensor does not detect filament movement (and run the |
@TheJoshW i think that's an accurate description of what happens. However i think we may want/need a config switch to allow it to only act when a print is running. Here were the steps I performed and results i saw:
The reason i believe that #3 is triggering the logic is that there is slack between the extruder and sensor. Here is my crude ASCII drawing of how the filament is ran on my Voron 2.4
Until that slack is tightened all E movements will trigger the runout. I also see it trigger while the print is in Here's the scenario i see during a filament change:
Now its possible to use the
|
@kalinon thanks for the details. As per my previous comments, pause/resume doesn't actually change the printer state, so you can move the print head and extrude while in pause. Idle timeout is the closest thing to printer state, however any movement of the print head or extruder puts the printer in "printing" state even when it is paused. So as a fail-safe I made the filament_motion_sensor monitor all extruder movement. It is possible to disable the sensor when in pause mode and I am happy to do that, however, this doesn't account for the time before the print starts and the printer isn't printing, nor is it in pause. Happy to take suggestions to handle this state. The other thing is filament slack. I have this issue as well, as my sensor is on the top of the printer, I increased the |
@TheJoshW Yeah, my issue was that in my You seem to have a good grasp on the state changes of the print cycle so I will defer to you on that behavior. Im still learning klipper and its differences from marlin. I do think perhaps a config option such as Ive modified most my gcode commands to handle the current behavior, but am having it almost always trigger when it starts to do the standard |
@TheJoshW I think there is a bug. If the sensor is disabled it will still trigger an action:pause if a runout is detected. You should be able to test this by having an empty extruder, then disabling and extruding via:
Mainsail log:
|
@kalinon Thanks for the update. I see the problem in |
Interesting, thanks. As a high-level feecback, this looks like useful functionality. I have not performed a full review, but I did notice a few items:
Cheers, |
I barge in just to provide an idea for future development. In #2610 a design using a magnetometer is provided which would allow extremely high measurement accuracy (potentially microns of filament motion). Maybe this filament run-out detection plugin could be sometimes in the future expanded to provide continuous feedback to be used to verify not only the presence of motion, but also the consistency between commanded and effective filament motion, a sort of closed loop feedback for filament motion. |
@KevinOConnor thanks for taking a look at this and providing your expert opinion.
I will back this change out.
Yep agree with the printer.send_event() method use. I have tried to make it as quick as possible and perform any time consuming actions in a greenlet. The work in #3832 looks very promising and I would be happy to use it. Let me know how you would like to proceed, i.e. is the use of printer.send_event() ok for now, with the plan to refactor at a later date with the changes from #3832?
Thanks I will look at this. filament_runout_sensor.py uses arbitrary timeouts which I removed in favour of actual state, so happy to feed these changes back to filament_runout_sensor.py as well. I didn't want to affect too much of the existing code on my first change. |
Sorry, I'm new. Does this mean I can add a sensor now? |
Thanks Kevin, I'll think about that and do more testing, maybe keep a prev_extruder_pos to detect retractions and act appropriately. Will also incorporate Arksine's suggestion plus some other enhancements if I get to them. Will raise another PR when I am ready. |
Are there any debug values that can be output for this module? I found some fault-positive jam detection when printing the first layer. Also, there is no info/log output when an error detected. |
any doc or quick start guide to try this? i have btt smart filament sensor to try. but lost in how set this. any clue? thanks |
See the filament_motion_sensor section of https://www.klipper3d.org/Config_Reference.html. It's the same as the filament_switch_sensor but with the addition of detection_length (default of 7 should be ok) and extruder (usually extruder). And you need to specify the switch_pin the sensor is connected to. |
@TheJoshW thanks... already set and working.... at least my print can resume. thanks a lot for this feature |
I have one of the BIGTREETECH Smart Filament Sensor Filament Break Detection Module sitting on a shelf. I bouoght it then switched to klipper so never used it. It sounds like this implementation would support it. Is there documentation, or examples on setting getting it running with klipper? |
Hi, question from my side. Some time ago I design rotary sensor for my Duet board and RRF (https://www.thingiverse.com/thing:3879971) if I good understand I could use it with those implementation? Also did you check performance of such sensor? Currently with 44 teeth I get resolution around 0,5mm. |
I added this section to my printer.cfg The minimum length of filament pulled through the sensor to triggera state change on the switch_pinDefault is 7 mm.extruder: extruder The name of the extruder section this sensor is associated with.This parameter must be provided.switch_pin: PC12 See the "filament_switch_sensor" section for a description of theabove parameters.I also commented out my filament_switch_sensor section. I connected the "smart sensor and tried it. It draws the first line (purge) the errors with filament out. I tried changing the switch pin to !PC12 and got the same result. I'm running klipper version v0.9.1-400 with fluidd v1.11.2. |
@markwinger yea that should work. See my previous comment: See the filament_motion_sensor section of https://www.klipper3d.org/Config_Reference.html. It's the same as the filament_switch_sensor but with the addition of detection_length (default of 7 should be ok) and extruder (usually extruder). And you need to specify the switch_pin the sensor is connected to. Commenting out filament_switch_sensor is also correct and switch_pin should be the same as the filament_switch_sensor. I have not added debugging or calibration functionality yet. |
@Cosik hi, if your sensor toggles the switch_pin then it should work. The filament_motion_sensor is pretty basic it just waits for a change in state then resets the runout length. So you should get at least 0.5mm resolution I would assume based on the fact it triggers from 0 to 1 and from 1 to 0. |
Add functionality to support a Filament Motion Sensor for detecting extruder jams as well as runouts. Works by an encoder toggling the switch_pin 0/1 as the filament is pulled through the sensor. Signed-off-by: Joshua Wherrett <thejoshw.code@gmail.com>
Add functionality to support a Filament Motion Sensor for detecting extruder jams as well as runouts. Works by an encoder toggling the switch_pin 0/1 as the filament is pulled through the sensor. Signed-off-by: Joshua Wherrett <thejoshw.code@gmail.com>
@TheJoshW i already used this feature. but something have bad behaviour. if my length used 6-8mm it is randomely pause but it will resume immidietly. but the weird is, resume process looks like not call. the height of the z axis is not return. it will return after several second. if i used 10mm it will paused randomly but it the filament is not jam or not runout. there is 2 problem here. hope you can check or gave some clue |
@tjengbudi this is a basic sensor so it could be a wiring issue or a bug if your print has a long retraction just after the runout length is reached. Making the extruder go backwards then trigger runout multiple times. If you can answer these questions it may help: Are you using BTT smart filament sensor? Thanks. |
@TheJoshW if it is at 6-8mm and it is auto resume after pause. the z position is not return. it just return printing but it like print in the air. cannot make sure x and y position returned or not the cable is used twisted cable. |
@tjengbudi I have a direct extruder with the BTT smart filament sensor mounted on the top of my printer. I have my detection_length set to 35 to compensate. This works fine for runout but may be to much distance if there is a jam. Ideally the sensor should be as close as possible to the extruder so every extrusion and retraction is accurately detected by the sensor. As for your issue with auto-resume, I did not write that code it is part of the filament switch sensor which the motion sensor is based on. I hope that helps. |
I'll be building my own filament motion sensor this weekend so I am eager to test this. Moving away from using just a simple switch that doesn't detect a snapped filament. One thing I am worried about, I'm putting the sensor outside of my enclosure, closer to the spool, and wondering how having about 300mm of filament between the sensor and extruder will mess with things. It is a direct drive and I'm not too worried about "wasting" that length, more about saving a print. With that length basically acting like a buffer I don't think having a longer length in the settings would be an issue.
The instance I can think of actually wanting to change this setting mid-print would be more if you're having issues. It would be nice to be able to adjust it on the fly to dial it in if you have false triggers on a really long print without just flat out disabling it. |
@charredchar Hi. Happy to do that, however I am not sure how I can "append" DETECTION_LENGTH to the existing SET_FILAMENT_SENSOR command, will need to look into that. As for your configuration, I have exactly the same setup. I set detection_length to 35 and it works fine. The only issue is when a jam occurs you will print for a bit longer without filament until 35 mm is fed through and the jam actually triggers. Hope this helps. |
I've just built a filament motion sensor using a standard rotary optical encoder. The encoder provides a quadrature output (Two pins, when A leads B CW, B leads A CCW) allowing the reader to determine which direction the sensor is rotating, something like this may help with problems where retraction reads like extrusion. My ideal scenario would be where the sensor reader would know roughly how much extrusion (positive or negative) is due during period and would trigger when the measured value deviated too much from the expected value. Being able to debug log the extrusion and sensed extrusion might also allow you to identify extrusion errors (Slip, jam, grind, etc). From what I see in filament_motion_sensor.py the sensor code does read the current extrusion position (I assume that's a current sum that includes retraction so can shrink as well as grow?) but the sensor trigger is just used as a heartbeat rather than a calibrated counter (I am a developer but python isn't my preferred language so I might be misunderstanding) if I'm reading this right I could have a go at, say "filament_speed_sensor.py" that actually compares extrusion to the sensed value. everything in /extras seems to be auto loaded so it doesn't look like it would need any changes elsewhere. My question is has this notion been rejected or perhaps is already being worked on, being new to Klipper I don't want to mess with existing effort or retread old ground. |
Hi @Curtis-Fletcher. Another user, @Sineos, also requested a similar feature, I haven't got around to it, however it sounds like your sensor is different enough to warrant a new plugin that includes this extended functionality. Have a look at previous comments in this PR and check out the issues mentioned by @Sineos. |
@TheJoshW i have a problem with the filament motion sensor. it is working until it detect the filament jam, i checked in the filament sensor status it gets error. after resume the filament sensor status is still error. if the filament jam again it will not detect again. it will resolve until i restart the klipper have you experienced about this ? i think it is not wrong in my setting. i open the issue but looks like the issue will be ignored and closed. |
looks like you have same problem with me #4540 (comment) |
@tjengbudi I am reusing the RunoutHelper from filament_switch_sensor. It works on state change so after a jam or runout you must pull filament through the sensor to change its state to "filament present" otherwise future jams will not be detected. |
@TheJoshW so it is known problem? |
@tjengbudi That's how all |
@TheJoshW i see. there is no way out? how if the filament not changing it will cannot not resume? i think it will the most safety use case |
@tjengbudi, I don't believe paused is a Klipper state. Pause simply tells the host to stop automatically sending gcode to Klipper (and run a macro if defined). If the user wants to manually send gcode to move or run a macro etc they can and Klipper won't stop them. This also applies to "resuming" which restores the printer state to when pause was requested and tells the host to resume streaming gcode. This has nothing to do with the filament runout sensor. If I understand correctly what you are asking, you want Klipper to check for a filament jam or runout and block the resume command until the issue is rectified. This could be complemented with a gcode mux_command of RESET_JAM which would allow the user to use gcode to clear the jam detection (in the case of a false positive). This will change the function of Klipper outside of the scope of the filament_motion_sensor and I will need to defer to @KevinOConnor and @Arksine to see if this is desired for Klipper. |
@TheJoshW oh i see. but looks like it is a bug that it can print without filament even the sensor get notified. if it is not prevent the printer to resume printing, at least it can detect another jam without must change the filament. as you said, i also have problem with second printing (without restart the klipper service), sometime it have random paused and sometime it is automatically resume after that if my pla broken it will not notified at all. or event the extruder never extrude. (known problem you said before) |
Add functionality to support a Filament Motion Sensor for detecting extruder jams as well as runouts. Works by an encoder toggling the switch_pin 0/1 as the filament is pulled through the sensor.
Everything seems to work ok, except I have seen some weirdness in pause_resume. When pausing, the printer runs the runout_gcode however it sometimes moves back over the print job (does not affect Z, only X (and maybe Y)). Increasing the pause_delay may resolve this.
Also pause_resume seemed a little inconsistent in how it was handled so I tried to address, not sure if this is ideal but it should resolve most issues and get people going using this plugin. I have documented this in detail in FilamentMotionSensor.md.
Resolves #1327
Resolves #886
Resolves #249
Resolves #3715
Signed-off-by: Joshua Wherrett thejoshw.code@gmail.com