Motion analysis by stepper phase

A couple of months ago I attempted to see if the “motion analysis” (motan) tools could be used to facilitate spreadCycle tuning. The high-level idea was to use an adxl345 accelerometer as a substitute for a “current probe” during the tuning process. That is, to see if it is possible to detect mechanical vibrations induced by poor TMC driver settings and use that as a tool for finding good TMC driver settings.

Unfortunately, the experiment didn’t work well, at least on my Voron Zero test printer. No matter what settings I chose, I couldn’t induce a mechanical jitter (or, at least couldn’t find jitter in the data with my simple analysis tools).

The test code is available at: https://github.com/KevinOConnor/klipper-dev/tree/work-motan-20211124

The code is very raw and likely only of interest to other developers.

At a high-level the analysis idea involves creating macros (see config/sample-phase.cfg on that branch) that emit timestamps (via action_call_remote_method("motan_log")) at the start and end of particular test events. This data is recorded using the ./scripts/motan/data_logger.py tool. It can then be analyzed by the new ./scripts/motan/phase_graph.py tool. That tool collates the data by stepper phase, determines the median value for each sensor for each stepper phase, and then graphs the results. Unfortunately, the phase_graph.py tool is currently pretty slow (on some of my tests it could take a few minutes even when run on a desktop class machine).

@dmbutyugin - FYI. I saw that you did something similar. I haven’t looked closely at your implementation, but I thought I would publish my previous work in this area in case it is interesting to you.

-Kevin

Here is an example graph I generated after modifying the TMC HEND setting:

According to the TMC specs, I should have seen some increased jitter on low HEND values. But, as a whole, all the tests show remarkably similar results. (There is variation, but it seems mostly to be run-to-run variance and not indicative of a change behavior due to HEND tuning.)

Since running the above test I found that my stepper motors were set to irun=16 when they could have been set to irun=31 (see Rework tmc run_current selection to prefer vsense=1 by KevinOConnor · Pull Request #5150 · Klipper3d/klipper · GitHub ) and it seems that the HEND setting is impacted by irun. So, it’s possible I just need to rerun the test now that the steppers are using a better irun configuration.

It’s also possible that using a “median of values at each phase” isn’t a good way to detect induced mechanical jitter. An FFT analysis may be a better approach.

-Kevin

EDIT: FYI, in the graph above, the data on the left is for “forward direction moves” while the data on the right is for “reverse direction”.

EDIT2: FYI, the above graph was generated from data collected using a variant of the TMC_TEST_HEND macro found in config/sample-phase.cfg on the test branch. It was generated with the tool ./scripts/motan/phase_graph.py stest-20211212/hend_100.

@dmbutyugin - at Porting some idea's to Klipper, freq / amp modulated output shaper, (can someone suggest a proper name for this methodology?) - #7 by dmbutyugin you indicated that you saw a repeating pattern by phase during your accelerometer analysis.

I also saw a repeating pattern - as can be seen in the “HEND graph” above. There does appear to be a correlation between accelerometer and stepper phase, as well as a correlation between angle sensor data and stepper phase. There is also a pattern in the forward and reverse direction - and indeed the pattern seems to change slightly based on direction. It’s not entirely clear to me if the change in pattern due to direction change is due to a systemic difference or due to run-to-run variance. (Though stepper motor lag definitely dominates the angle sensor data and that is clearly influenced by direction.)

-Kevin

Thanks, Kevin. I think my approach is very similar, and only the implementation is somewhat different (I didn’t make any changes to emit timestamps, so I had to manually restrict the processing of the logged data to a regions of interest). I also used some numpy “magic”, like unique and reduceat functions to speed up the post-processing of the results considerably. The plot script works very smoothly on a desktop-class machine.

According to the TMC specs, I should have seen some increased jitter on low HEND values.

It might indeed be the case that the steppers are operating in such conditions that they are not exhibiting the jitter (it might be the case for 3D printers in general, or may be more specific to your configuration). TBH, from reading the TMC datasheets, it seemed that the jitter, even if present, could end up being high-frequency, something that accelerometer wouldn’t be able to detect (its limit is at 1600 Hz due to the sampling rate).

… indicated that you saw a repeating pattern by phase during your accelerometer analysis.

I think more like ‘reoccurring’? The generated pattern is ultimately accel(phase) and is not periodic. But it is periodically repeated (as phases periodically repeat themselves with time) in the charts for plotting purposes. Though the repeating pattern does exist in the raw accelerometer readings, just with some variability and noise at different positions.

There is also a pattern in the forward and reverse direction - and indeed the pattern seems to change slightly based on direction.

In my experiments, I could tell that the patterns between forward and reverse directions are reversed in the manner unexpected by me:

backward_accel(phase) ~= -forward_accel(num_phases-phase-1)

* I expected it to be

backward_accel(phase) ~= -forward_accel(phase)

I could tell that it is like this due to asymmetries in the forward_accel and backward_accel profiles. These asymmetries allows one to map different parts of the forward and backward motion to each other, and see that backward_accel(phase) != -forward_accel(phase) with high certainty.

It’s not entirely clear to me if the change in pattern due to direction change is due to a systemic difference or due to run-to-run variance.

In my experiments, this seems to be a systemic difference. That is, the profile itself and its assymmetries are repeatable across multiple runs of the same test (and even between different days with the machine powered off in between).

Yes. Some time after I ran these tests I tried going through the tmc2209 spreadcycle spreadsheet and I found that it too recommended a very low HEND. It was in that process that I found that HEND is dependent on IRUN and that I had a poor IRUN setting. I still need to rerun the tests with those changes.

I’ve found the accelerometer and angle sensors to be surprisingly accurate. If there is some jitter that it can’t pick up, I’d be surprised that “the print” could pick it up either. So, same end result - nothing to tune. That said, as above, the sensors (and “print”) may observe the issue, but my analysis of the data may be lacking.

I agree the data should be mirrored. I’m not sure I understand what you are reporting though. I updated my phase_graph.py tool and ran your data through it:


This is with commit 17fb2bd2 and the command: ./scripts/motan/phase_graph.py dtest-20220124/test_x -m 'tmc5160 stepper_x' -r '[[3.25, 5.65, "x"], [6.3, 8.7, "x"]]' -g '[["adxl345(hotend,x)"]]'

It looks to me like the “reverse” graph is mirrored across the X axis and is shifted about a quarter full step to the left. This seems about right to me - the acceleration is mirrored because of different movement direction and the phases are shifted due to stepper lag. This was with stealthChop, I assume? Am I missing something?

-Kevin

EDIT: It seems the graph labels are a little misleading in the graph above. I think the left graph is actually the “negative cartesian x motion” and the right graph is “positive cartesian x motion”. The tmc driver application of phases is goofy, so it’s not immediately clear to me which one is “incrementing phase” and which one is “decrementing phase”.

If there is some jitter that it can’t pick up, I’d be surprised that “the print” could pick it up either.

I agree. I mean it more like, high-frequency jitter may result in unpleasant noise, hissing, and/or higher power dissipation in stepper motors.

I agree the data should be mirrored. I’m not sure I understand what you are reporting though.

Well, I was reporting that you not only need to mirror over Y axis, but also X axis. This is unexpected by me. For instance, if you think about detent forces in the stepper, such force F depends only on the position: F = F(phase). It won’t mirror if the stepper rotates in the opposite direction. However, the data suggests that whatever forces are acting on the toolhead during constant speed motion get flipped when direction is reversed. Essentially, accel_backward(phase=10) == -accel_forward(phase=1013) and accel_backward(phase=500) = -accel_forward(523).

Why I think it matters: if that’s really true, it makes a simple output_shaper like

X'(t) = OS(X(t))

infeasible. In fact, earlier I did some experimentation where I tried to make an output shaper per stepper motor based on cubic splines. And indeed I was able to tune it on a forward motion somewhat to reduce the amplitude of vibrations, say, in the forward motion, from ~10K mm/sec^2 to ~1K mm/sec^2, which indicates that it sort of works. However, the backward motion was not affected so much, and I did not observe a reduction in the vibrations when the toolhead moves backwards. So, you need to compensate for forward motion and backwards motion differently. This also indirectly confirms the results I showed above.

And ultimately, well, it’s too bad. Because it seems that a simple output shaper won’t work. Not unless some clever scheme can be devised, which I’m not sure is possible. Of course, I may be missing something.

… phases are shifted due to stepper lag. This was with stealthChop, I assume?

No, as I mentioned in the other thread, this was done in SpreadCycle mode and 256 microstepping mode without interpolation. I used TMC spreadsheet to calculate the SpreadCycle parameters using the theoretical data from the stepper datasheet (it probably does not matter much, I just mention it for completeness).

[tmc5160 stepper_x]
...
interpolate: False
run_current: 0.800
stealthchop_threshold: 0
# For 17HS15-1504S
driver_TBL: 2
driver_TOFF: 3
driver_HSTRT: 2
driver_HEND: 3

The tmc driver application of phases is goofy, so it’s not immediately clear to me which one is “incrementing phase” and which one is “decrementing phase”.

[stepper_x]
dir_pin: P2.6

so this probably means that the forward motion [3.25, 5.65] has phase increasing, and backwards motion [6.3, 8.7] - decreasing.

EDIT: to clarify: the experiments I did with the output shaper were also done in SpreadCycle mode, where it makes sense to adjust the timing of the stepper pulses. That’s not really viable in StealthChop mode.

Okay, I understand.

FWIW, I didn’t notice a similar pattern on my Voron Zero. That may be due to corexy kinematics and also possibly more measurement noise in general.

I need to rewire the accelerometer to my Zero to run more tests. But, just as an example, I graphed a random segment of data from a capture taken a couple of months ago:

I looked into that further last night. In case you are curious, the Klipper code always reports an incrementing step phase with an incrementing nominal stepper position. So, for example, if on a cartesian axis, then a positive X move will result in a positive nominal stepper position, and thus an increasing reported stepper phase. On the tmc drivers, a non-inverted dir_pin will actually result in a mirroring of the reported step phase (reported_phase = 1023 - tmc_phase). So, on your particular printer, with a positive X move, the TMC driver will actually be internally decrementing the step phase. That said, it also occurred to me last night that this doesn’t matter, as the tmc sine wave is always a mirror image of itself anyway. So, it doesn’t really matter if it is incrementing or decrementing internally.

-Kevin

P.S. Graph above was with corrected labels (commit 58a3d5a6) and with: ./scripts/motan/phase_graph.py stest-20211129/moves_10 -m 'tmc2209 stepper_x' -r '[[28.0, 28.5, "x"], [29.0, 29.5, "x"]]' -g '[["adxl345(adxl345,x)"],["deviation(angle(angle_x),stepq(stepper_x))"]]'