Commit 97badd38 authored by Nicholas Gar Hei Chan's avatar Nicholas Gar Hei Chan
Browse files

Code comments

parent c0fe46cb
# coding=utf-8
from __future__ import absolute_import
### (Don't forget to remove me)
# This is a basic skeleton for your plugin's You probably want to adjust the class name of your plugin
# as well as the plugin mixins it's subclassing from. This is really just a basic skeleton to get you started,
# defining your plugin as a template plugin, settings and asset plugin. Feel free to add or remove mixins
# as necessary.
# Take a look at the documentation on what other plugin mixins are available.
import subprocess
import time
import threading
......@@ -22,7 +14,7 @@ import sampler
import flask
sampling = 0
sampling = 0 # Global flag for when sampling is in progress
class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
......@@ -40,13 +32,15 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
layer: gcodeparser.Layer
layer : gcodeparser.Layer
Layer object to send to the client.
# Create a dictionary containing the SVG image in plaintext
data = dict(layer_svg=self.model.layers[layer].to_svg_inline(500,
self.model.max_x, self.model.max_y),
# Send the data dictionary to the client
self._plugin_manager.send_plugin_message(self._identifier, data)
def process_gcode(self, payload):
......@@ -54,7 +48,7 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
payload: dict
payload : dict
File selected payload from the on-event handler.
num_pts = int(self._settings.get(['sampling_points']))
......@@ -62,7 +56,9 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
method = self._settings.get(['sampling_algo'])'Processing GCODE with {} layer spacing, {} samples per layer and {}'.format(spacing, num_pts, method))
# Uploaded GCODE files are stored under ~/.octoprint/uploads
full_path = os.path.expanduser("~/.octoprint/uploads/{}".format(payload['name']))
# Process GCODE file with parse_code function
self.model = gcp.parse_gcode(full_path,spacing, num_pts, method)
self.num_layers = len(self.model.layers)
self.curr_layer = 0;
......@@ -70,35 +66,53 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
def sample_layer(self, current_layer):
""" Sample a layer
current_layer : int
layer to sample
layer = []
next_height = []
# Skip the first layer
if current_layer != 0:
layer = self.model.layers[current_layer-1]
next_height = self.model.layers[current_layer].z_height
return True
# Inner function for operating the probe
def probe_process(self, layer, next_height):"Starting sampling run at Z={}".format(layer.z_height))
# Initialize the output as true to begin
result = True
# Iterate through each sample point
for point in zip(layer.sample_points['x'], layer.sample_points['y']):
# Probe each point, if the result is good, continue. If not, return a bad reading
if self.probe_point(point[0], point[1], layer.z_height):"Good reading at X={}, Y={}".format(point[0], point[1]))
else:"Bad reading at X={}, Y={}".format(point[0], point[1]))
result = False
# At the end of the sampling process, re-extrude by the retraction amount
if result:
self._printer.extrude(float(self._settings.get(['retraction'])), None, None)
# Pause the print if something went wrong
# self._printer.commands("G0 Z{}".format(next_height))
# Release the job lock
# If there are points to sample
if len(layer.sample_points['x']):
# Retract by the specified amount
self._printer.extrude(float(self._settings.get(['retraction'])), None, None)
# Set the job on hold
if self._printer.set_job_on_hold(True):
# Start a new thread for probing, allows other Octoprint functions to continue running
thread = threading.Thread(target=probe_process, args=[self,layer,next_height])
thread.daemon = True
......@@ -109,29 +123,42 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
def probe_point(self, x, y, z):
Probe at selected x,y,z position. Move probe to point, extend probe, measure output, and report result
x : float
X coordinate of probe point
y : float
Y coordinate of probe point
z : float
Z coordinate of probe point
# The machine coordinates are calculated by adding/subtracting the offset
probe_x = x - self.offsets['x']
probe_y = y - self.offsets['y']
probe_z = z + self.offsets['z']
# Check if any coordinate is negative, ignore if it is.
# Could add check for coordinates exceeding maximum build dimensions, though need user to input
if (probe_x < 0) or (probe_y < 0) or (probe_z < 0):'Sample point outside of printer bounds. Assuming good')
return True
# Go to the sample position, accounting for tool offset
command = 'G0 F4329 X{} Y{}'.format(probe_x, probe_y)
# Send a combination of "G4 P0" and "M114" command to wait for printer to get to position
self._printer.commands('G4 P0')
self.movement_lock = True
# Block until the movement lock is cleared
# Run the probe with solenoid pin = 7, sense pin = 0, and delay time = 0.15s
reading = sampler.sample_probe(7, 0, 0.15)"./", capture_output=True).stdout.decode("utf-8").strip() == '0'
return reading
# ------------------------------------------------------------------------- #
......@@ -161,44 +188,48 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
def on_api_command(self, command, data):
if command == "change_layer":
if command == "change_layer": # Called when layer change buttons are pressed
# Check if the user wants to increment or decrement layer, and send the requested layer
if data["inc"] == "+1" and self.curr_layer < self.num_layers - 1:
self.curr_layer += 1
if data["inc"] == "-1" and self.curr_layer > 0:
self.curr_layer -= 1
elif command == "reload_model":
elif command == "reload_model": # Called when the reload button is pressed
if self.file_payload:'reloading model')
self.on_event('FileSelected', self.file_payload)
else:'no GCODE selected')
elif command == "test_command":
##~~ EventHandlerPlugin mixin
def on_event(self, event, payload):
global sampling
if event == 'FileSelected':
if event == 'FileSelected': # Event called when a user selects a file'File selected: "{}" at path "{}"'.format(payload['name'], payload['path']))
self.file_payload = payload
# Start processing the GCODE file
self.process_gcode(payload)'GCODE Processed: {} layers'.format(self.num_layers))
# Send the first layer image to the GCODE viewer
# Event for change in Z. Only runs if autoFDP is enabled.
if event == 'ZChange' and self._settings.get(['enable'])==True:
# Get printer coordinates
data = self._printer.get_current_data()
# Find the current Z coordinate
currentZ = data['currentZ']
# Check if current Z-height is a valid layer
current_layer = self.model.layer_heights.index(currentZ)'Current layer: {}'.format(current_layer))
self._printer.extrude(float(self._settings.get(['retraction'])), None, None)
# Start the sampling procedure
self.sample_layer(current_layer)'Finished sampling run')
except:'Not a valid layer at z = {}'.format(currentZ))
# Event called when the M114 response is received. Clears the movement lock if set
if event == 'PositionUpdate' and self._settings.get(['enable'])==True:
if self.movement_lock == True:
self.movement_lock = False
......@@ -212,8 +243,8 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
def on_after_startup(self):"autoFDP starting, retrieving saved settings...")
# Initialize settings
self.offsets['x'] = float(self._settings.get(['x_offset']))
self.offsets['y'] = float(self._settings.get(['y_offset']))
self.offsets['z'] = float(self._settings.get(['z_offset']))
......@@ -235,16 +266,15 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
def on_settings_save(self, data):
octoprint.plugin.SettingsPlugin.on_settings_save(self, data)"SETTINGS HAVE BEEN CHANGED")['enable']))['sampling_algo']))
#TODO: PROBE UPDATE CODE HERE"Settings changed!")
self.offsets['x'] = float(self._settings.get(['x_offset']))
self.offsets['y'] = float(self._settings.get(['y_offset']))
self.offsets['z'] = float(self._settings.get(['z_offset']))['enable']) == "True")['enable']) == True)
##~~ AssetPlugin mixin
def get_assets(self):
# Define your plugin's asset files to automatically include in the
......@@ -263,7 +293,7 @@ class AutofdpPlugin(octoprint.plugin.SettingsPlugin,
# for details.
return dict(
displayName="Autofdp Plugin",
displayName="AutoFDP Plugin",
# version check: github repository
if grep -q "Raspberry Pi" /proc/cpuinfo; then
gpio mode 0 in
gpio mode 7 out
gpio write 7 1
sleep 0.2
gpio read 0
gpio write 7 0
sleep 2
echo 1
......@@ -3,6 +3,18 @@ import subprocess
import time
def sample_probe(solenoid_pin, sense_pin, delay_time):
"""Actuate and read results from fault detection probe.
solenoid_pin : int
Raspberry Pi GPIO pin for the solenoid
sense_pin : int
Raspberry Pi GPIO pin for hall effect sensor
delay_time : float
Time to wait between actuating probe and reading sensor
os.system("gpio mode {} in".format(sense_pin))
os.system("gpio mode {} out".format(solenoid_pin))
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment