extruder: Create a new class and python file to track the printer extruder

Create a new python file (extruder.py) to control the extruder heater
and stepper motors.  This separates the extruder control logic from
the cartesian robot code - making it easier to customize both the
kinematic control of the robot as well as the extruder.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2016-07-10 12:23:35 -04:00
parent 4a527a46ce
commit af99ab1645
8 changed files with 88 additions and 27 deletions

View File

@ -42,7 +42,7 @@ position_min: 0.1
position_endstop: 0.5 position_endstop: 0.5
position_max: 200 position_max: 200
[stepper_e] [extruder]
# Pins: PC3, PC2 # Pins: PC3, PC2
step_pin: ar19 step_pin: ar19
dir_pin: ar18 dir_pin: ar18
@ -50,8 +50,6 @@ enable_pin: ar25
step_distance: .004242 step_distance: .004242
max_velocity: 200000 max_velocity: 200000
max_accel: 3000 max_accel: 3000
[heater_nozzle]
heater_pin: ar4 heater_pin: ar4
thermistor_pin: analog1 thermistor_pin: analog1
thermistor_type: EPCOS 100K B57560G104F thermistor_type: EPCOS 100K B57560G104F

View File

@ -77,19 +77,19 @@ position_min: 0.1
position_endstop: 0.5 position_endstop: 0.5
position_max: 200 position_max: 200
# The stepper_e section is used to describe the stepper controlling # The extruder section is used to describe both the stepper
# the printer extruder. It has the same settings as the stepper_x # controlling the printer extruder and the heater parameters for the
# section # nozzle. The stepper configuration has the same settings as the
[stepper_e] # stepper_x section and the heater configuration has the same settings
# as the heater_bed section
[extruder]
step_pin: ar19 step_pin: ar19
dir_pin: ar18 dir_pin: ar18
enable_pin: !ar25 enable_pin: !ar25
step_distance: .004242 step_distance: .004242
max_velocity: 200000 max_velocity: 200000
max_accel: 3000 max_accel: 3000
# The remaining variables describe the extruder heater
# The heater_nozzle section describes the extruder and extruder heater
[heater_nozzle]
heater_pin: ar4 heater_pin: ar4
# PWM output pin controlling the heater # PWM output pin controlling the heater
thermistor_pin: analog1 thermistor_pin: analog1
@ -118,8 +118,7 @@ max_temp: 210
# this value) # this value)
# The heater_bed section describes a heated bed (if present - omit # The heater_bed section describes a heated bed (if present - omit
# section if not present). It has the same settings as the # section if not present).
# heater_nozzle section
[heater_bed] [heater_bed]
heater_pin: ar3 heater_pin: ar3
thermistor_pin: analog0 thermistor_pin: analog0

View File

@ -43,15 +43,13 @@ position_min: 0.1
position_endstop: 0.7 position_endstop: 0.7
position_max: 200 position_max: 200
[stepper_e] [extruder]
step_pin: PC3 step_pin: PC3
dir_pin: !PL6 dir_pin: !PL6
enable_pin: !PA4 enable_pin: !PA4
step_distance: .004242 step_distance: .004242
max_velocity: 200000 max_velocity: 200000
max_accel: 3000 max_accel: 3000
[heater_nozzle]
heater_pin: PH6 heater_pin: PH6
thermistor_pin: PF0 thermistor_pin: PF0
thermistor_type: EPCOS 100K B57560G104F thermistor_type: EPCOS 100K B57560G104F

View File

@ -6,14 +6,14 @@
import logging import logging
import stepper, homing import stepper, homing
StepList = (0, 1, 2, 3) StepList = (0, 1, 2)
class CartKinematics: class CartKinematics:
def __init__(self, printer, config): def __init__(self, printer, config):
steppers = ['stepper_x', 'stepper_y', 'stepper_z', 'stepper_e'] steppers = ['stepper_x', 'stepper_y', 'stepper_z']
self.steppers = [stepper.PrinterStepper(printer, config.getsection(n)) self.steppers = [stepper.PrinterStepper(printer, config.getsection(n))
for n in steppers] for n in steppers]
self.stepper_pos = [0, 0, 0, 0] self.stepper_pos = [0, 0, 0]
def build_config(self): def build_config(self):
for stepper in self.steppers: for stepper in self.steppers:
stepper.build_config() stepper.build_config()
@ -31,9 +31,6 @@ class CartKinematics:
accel_factor = min([self.steppers[i].max_accel / abs(axes_d[i]) accel_factor = min([self.steppers[i].max_accel / abs(axes_d[i])
for i in StepList if axes_d[i]]) for i in StepList if axes_d[i]])
return velocity_factor * move_d, accel_factor * move_d return velocity_factor * move_d, accel_factor * move_d
def get_max_e_speed(self):
s = self.steppers[3]
return s.max_velocity, s.max_accel
def home(self, toolhead, axis): def home(self, toolhead, axis):
# Each axis is homed independently and in order # Each axis is homed independently and in order
homing_state = homing.Homing(toolhead, self.steppers) # XXX homing_state = homing.Homing(toolhead, self.steppers) # XXX

62
klippy/extruder.py Normal file
View File

@ -0,0 +1,62 @@
# Code for handling printer nozzle extruders
#
# Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
import stepper, heater
class PrinterExtruder:
def __init__(self, printer, config):
cfg = config.getsection('extruder')
self.heater = heater.PrinterHeater(printer, cfg)
self.stepper = stepper.PrinterStepper(printer, cfg)
self.stepper_pos = 0
def build_config(self):
self.heater.build_config()
self.stepper.build_config()
def get_max_speed(self):
return self.stepper.max_velocity, self.stepper.max_accel
def motor_off(self, move_time):
self.stepper.motor_enable(move_time, 0)
def move(self, move_time, move):
inv_accel = 1. / move.accel
new_step_pos = int(move.pos[3]*self.stepper.inv_step_dist + 0.5)
steps = new_step_pos - self.stepper_pos
if not steps:
return
self.stepper_pos = new_step_pos
sdir = 0
if steps < 0:
sdir = 1
steps = -steps
clock_offset, clock_freq, so = self.stepper.prep_move(sdir, move_time)
step_dist = move.move_d / steps
step_offset = 0.5
# Acceleration steps
#t = sqrt(2*pos/accel + (start_v/accel)**2) - start_v/accel
accel_clock_offset = move.start_v * inv_accel * clock_freq
accel_sqrt_offset = accel_clock_offset**2
accel_multiplier = 2.0 * step_dist * inv_accel * clock_freq**2
accel_steps = move.accel_r * steps
step_offset = so.step_sqrt(
accel_steps, step_offset, clock_offset - accel_clock_offset
, accel_sqrt_offset, accel_multiplier)
clock_offset += move.accel_t * clock_freq
# Cruising steps
#t = pos/cruise_v
cruise_multiplier = step_dist * clock_freq / move.cruise_v
cruise_steps = move.cruise_r * steps
step_offset = so.step_factor(
cruise_steps, step_offset, clock_offset, cruise_multiplier)
clock_offset += move.cruise_t * clock_freq
# Deceleration steps
#t = cruise_v/accel - sqrt((cruise_v/accel)**2 - 2*pos/accel)
decel_clock_offset = move.cruise_v * inv_accel * clock_freq
decel_sqrt_offset = decel_clock_offset**2
decel_steps = move.decel_r * steps
so.step_sqrt(
decel_steps, step_offset, clock_offset + decel_clock_offset
, decel_sqrt_offset, -accel_multiplier)

View File

@ -35,7 +35,10 @@ class GCodeParser:
self.axis2pos = {'X': 0, 'Y': 1, 'Z': 2, 'E': 3} self.axis2pos = {'X': 0, 'Y': 1, 'Z': 2, 'E': 3}
def build_config(self): def build_config(self):
self.toolhead = self.printer.objects['toolhead'] self.toolhead = self.printer.objects['toolhead']
self.heater_nozzle = self.printer.objects.get('heater_nozzle') self.heater_nozzle = None
extruder = self.printer.objects.get('extruder')
if extruder:
self.heater_nozzle = extruder.heater
self.heater_bed = self.printer.objects.get('heater_bed') self.heater_bed = self.printer.objects.get('heater_bed')
self.fan = self.printer.objects.get('fan') self.fan = self.printer.objects.get('fan')
self.build_handlers() self.build_handlers()

View File

@ -5,7 +5,7 @@
# #
# This file may be distributed under the terms of the GNU GPLv3 license. # This file may be distributed under the terms of the GNU GPLv3 license.
import sys, optparse, ConfigParser, logging, time, threading import sys, optparse, ConfigParser, logging, time, threading
import gcode, toolhead, util, mcu, fan, heater, reactor import gcode, toolhead, util, mcu, fan, heater, extruder, reactor
class ConfigWrapper: class ConfigWrapper:
def __init__(self, printer, section): def __init__(self, printer, section):
@ -52,9 +52,9 @@ class Printer:
if self.fileconfig.has_section('fan'): if self.fileconfig.has_section('fan'):
self.objects['fan'] = fan.PrinterFan( self.objects['fan'] = fan.PrinterFan(
self, ConfigWrapper(self, 'fan')) self, ConfigWrapper(self, 'fan'))
if self.fileconfig.has_section('heater_nozzle'): if self.fileconfig.has_section('extruder'):
self.objects['heater_nozzle'] = heater.PrinterHeater( self.objects['extruder'] = extruder.PrinterExtruder(
self, ConfigWrapper(self, 'heater_nozzle')) self, ConfigWrapper(self, 'extruder'))
if self.fileconfig.has_section('heater_bed'): if self.fileconfig.has_section('heater_bed'):
self.objects['heater_bed'] = heater.PrinterHeater( self.objects['heater_bed'] = heater.PrinterHeater(
self, ConfigWrapper(self, 'heater_bed')) self, ConfigWrapper(self, 'heater_bed'))

View File

@ -61,6 +61,8 @@ class Move:
# Generate step times for the move # Generate step times for the move
next_move_time = self.toolhead.get_next_move_time() next_move_time = self.toolhead.get_next_move_time()
self.toolhead.kin.move(next_move_time, self) self.toolhead.kin.move(next_move_time, self)
if self.axes_d[3]:
self.toolhead.extruder.move(next_move_time, self)
self.toolhead.update_move_time(accel_t + cruise_t + decel_t) self.toolhead.update_move_time(accel_t + cruise_t + decel_t)
# Class to track a list of pending move requests and to facilitate # Class to track a list of pending move requests and to facilitate
@ -113,6 +115,7 @@ class ToolHead:
def __init__(self, printer, config): def __init__(self, printer, config):
self.printer = printer self.printer = printer
self.reactor = printer.reactor self.reactor = printer.reactor
self.extruder = printer.objects.get('extruder')
self.kin = cartesian.CartKinematics(printer, config) self.kin = cartesian.CartKinematics(printer, config)
self.max_xy_speed, self.max_xy_accel = self.kin.get_max_xy_speed() self.max_xy_speed, self.max_xy_accel = self.kin.get_max_xy_speed()
self.junction_deviation = config.getfloat('junction_deviation', 0.02) self.junction_deviation = config.getfloat('junction_deviation', 0.02)
@ -208,7 +211,7 @@ class ToolHead:
move.process(0., 0.) move.process(0., 0.)
def _move_only_e(self, newpos, axes_d, speed): def _move_only_e(self, newpos, axes_d, speed):
self.move_queue.flush() self.move_queue.flush()
kin_speed, kin_accel = self.kin.get_max_e_speed() kin_speed, kin_accel = self.extruder.get_max_speed()
speed = min(speed, self.max_xy_speed, kin_speed) speed = min(speed, self.max_xy_speed, kin_speed)
accel = min(self.max_xy_accel, kin_accel) accel = min(self.max_xy_accel, kin_accel)
move = Move(self, newpos, abs(axes_d[3]), axes_d, speed, accel) move = Move(self, newpos, abs(axes_d[3]), axes_d, speed, accel)
@ -238,5 +241,6 @@ class ToolHead:
self.dwell(STALL_TIME) self.dwell(STALL_TIME)
last_move_time = self.get_last_move_time() last_move_time = self.get_last_move_time()
self.kin.motor_off(last_move_time) self.kin.motor_off(last_move_time)
self.extruder.motor_off(last_move_time)
self.dwell(STALL_TIME) self.dwell(STALL_TIME)
logging.debug('; Max time of %f' % (last_move_time,)) logging.debug('; Max time of %f' % (last_move_time,))