Well, there's code in Octolapse for this (position+position state+extruder tracking). I've been thinking of splitting it of into a separate plugin for other reasons (reuse).
However, Homing automatically is a problem since the printer might run into something (a non-removed print or something). Running it before the print starts is a really good idea that you suggested (most start gcode does this), but some folks do NOT do this for various reasons. Octolapse requires a home command, and I've fielded support requests where users manually home their prints and run gcode with no home. I actually added a pseudo G28 O
command that will tell Octolapse that the current position is the home position to support these situations, though the solution is still in flux.
Anyway, this is a really interesting idea that maybe deserves its own thread? I honestly think this could eventually be a bundled plugin since so many are reinventing the wheel to get an accurate position/axis mode, etc. The 'Display layer progress' plugin immediately comes to mind, as well as the exclude region plugin. I know DisplayLayerProgress has some issues with G91.
The Octolapse code definitely needs improvement/cleanup as well as more gcode implementation (only a small subset is supported), but it is the most advanced position/state tracking code I've seen in a plugin. We should discuss more.
Thanks for starting this thread. I'd like to know if anyone else wants extruder/xyz axis tracking. Here is an example of the position values (dict form) that Octolapse tracks (some aren't really useful outside of the context of Octolapse):
def to_position_dict(self):
return {
"F": self.F,
"X": self.X,
"XOffset": self.XOffset,
"Y": self.Y,
"YOffset": self.YOffset,
"Z": self.Z,
"ZOffset": self.ZOffset,
"E": self.E,
"EOffset": self.EOffset,
"Features": self.Features,
}
Here are the position state values:
def to_state_dict(self):
return {
"GCode": self.parsed_command.gcode,
"XHomed": self.XHomed,
"YHomed": self.YHomed,
"ZHomed": self.ZHomed,
"IsLayerChange": self.IsLayerChange,
"IsHeightChange": self.IsHeightChange,
"IsZHop": self.IsZHop,
"IsRelative": self.IsRelative,
"IsExtruderRelative": self.IsExtruderRelative,
"IsMetric": self.IsMetric,
"Layer": self.Layer,
"Height": self.Height,
"LastExtrusionHeight": self.LastExtrusionHeight,
"IsInPosition": self.IsInPosition,
"HasOneFeatureEnabled": self.HasOneFeatureEnabled,
"InPathPosition": self.InPathPosition,
"IsPrimed": self.IsPrimed,
"HasPositionError": self.HasPositionError,
"PositionError": self.PositionError,
"HasReceivedHomeCommand": self.HasReceivedHomeCommand,
"IsTravelOnly": self.IsTravelOnly
}
Here is the combined dict (both state and position):
def to_dict(self):
return {
"GCode": self.parsed_command.gcode,
"F": self.F,
"X": self.X,
"XOffset": self.XOffset,
"XHomed": self.XHomed,
"Y": self.Y,
"YOffset": self.YOffset,
"YHomed": self.YHomed,
"Z": self.Z,
"ZOffset": self.ZOffset,
"ZHomed": self.ZHomed,
"E": self.E,
"EOffset": self.EOffset,
"IsRelative": self.IsRelative,
"IsExtruderRelative": self.IsExtruderRelative,
"IsMetric": self.IsMetric,
"LastExtrusionHeight": self.LastExtrusionHeight,
"IsLayerChange": self.IsLayerChange,
"IsZHop": self.IsZHop,
"IsInPosition": self.IsInPosition,
"Features": self.Features,
"InPathPosition": self.InPathPosition,
"IsPrimed": self.IsPrimed,
"HasPositionError": self.HasPositionError,
"PositionError": self.PositionError,
"HasPositionChanged": self.HasPositionChanged,
"HasStateChanged": self.HasStateChanged,
"Layer": self.Layer,
"Height": self.Height,
"HasReceivedHomeCommand": self.HasReceivedHomeCommand
}
Here are the exturder state values that are tracked:
def to_dict(self):
return {
"E": self.E,
"ExtrusionLength": self.ExtrusionLength,
"ExtrusionLengthTotal": self.ExtrusionLengthTotal,
"RetractionLength": self.RetractionLength,
"DetractionLength": self.DetractionLength,
"IsExtrudingStart": self.IsExtrudingStart,
"IsExtruding": self.IsExtruding,
"IsPrimed": self.IsPrimed,
"IsRetractingStart": self.IsRetractingStart,
"IsRetracting": self.IsRetracting,
"IsRetracted": self.IsRetracted,
"IsPartiallyRetracted": self.IsPartiallyRetracted,
"IsDetractingStart": self.IsDetractingStart,
"IsDetracting": self.IsDetracting,
"IsDetracted": self.IsDetracted,
"HasChanged": self.HasChanged
}
I currently store the previous 5 state values, and the position is calculated ONLY at the queuing phase since I might manually change things by pausing and injecting code. The user would be responsible for submiting an 'Undo position update' if a gcode is altered/suppressed in the queuing phase. It would be trivial to also track the 'Sent' position, which would NOT be alterable and thus less dangerous to use.