Skip to content

Commit

Permalink
heaters implementation: extruder and bed, adding answers to gcode com…
Browse files Browse the repository at this point in the history
…mands
  • Loading branch information
Nikolay-Kha committed Jun 18, 2017
1 parent df7eba6 commit 5314694
Show file tree
Hide file tree
Showing 16 changed files with 602 additions and 53 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ perfect choice for easy development of this project.
Video demo - [YouTube video](https://youtu.be/vcedo59raS4)

# Current gcode support
Commands G0, G1, G2, G3, G4, G17, G18, G19, G20, G21, G28, G53, G90, G91, G92, M2, M3,
M5, M30 are supported. Commands can be easily added, see
[gmachine.py](./cnc/gmachine.py) file.
Commands G0, G1, G2, G3, G4, G17, G18, G19, G20, G21, G28, G53, G90, G91, G92,
M2, M3, M5, M30, M104, M105, M106, M107, M109, M114, M140, M190 are supported.
Commands can be easily added, see [gmachine.py](./cnc/gmachine.py) file.
Four axis are supported - X, Y, Z, E.
Circular interpolation for XY, ZX, YZ planes is supported.
Spindle with rpm control is supported.
Circular interpolation for XY, ZX, YZ planes is supported.
Extruder and bed heaters are supported.

# Config
All configs are stored in [config.py](./cnc/config.py) and contain hardware
Expand Down
14 changes: 14 additions & 0 deletions cnc/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
TABLE_SIZE_Z_MM = 48

SPINDLE_MAX_RPM = 10000
EXTRUDER_MAX_TEMPERATURE = 250
BED_MAX_TEMPERATURE = 100
MIN_TEMPERATURE = 40
EXTRUDER_PID = {"P": 0.0993079964195,
"I": 0.00267775053311,
"D": 0.267775053311}
BED_PID = {"P": 5.06820175723,
"I": 0.0476413193519,
"D": 4.76413193519}

# Pins config
STEPPER_STEP_PIN_X = 16
Expand All @@ -26,6 +35,11 @@
STEPPER_DIR_PIN_E = 8

SPINDLE_PWM_PIN = 7
FAN_PIN = 10
EXTRUDER_HEATER_PIN = 9
BED_HEATER_PIN = 11
EXTRUDER_TEMPERATURE_SENSOR_CHANNEL = 0
BED_TEMPERATURE_SENSOR_CHANNEL = 1

ENDSTOP_PIN_X = 12
ENDSTOP_PIN_Y = 6
Expand Down
9 changes: 9 additions & 0 deletions cnc/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,12 @@ class RotationDirection(Enum):

CW = RotationDirection("CW")
CCW = RotationDirection("CCW")


class Heaters(Enum):
""" Enum for selecting heater.
"""
pass

HEATER_EXTRUDER = Heaters("extruder")
HEATER_BED = Heaters("bed")
8 changes: 8 additions & 0 deletions cnc/gcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ def __init__(self, params):
"""
self.params = params

def has(self, arg_name):
"""
Check if value is specified.
:param arg_name: Value name.
:return: boolean value.
"""
return arg_name in self.params

def get(self, arg_name, default=None, multiply=1.0):
""" Get value from gcode line.
:param arg_name: Value name.
Expand Down
114 changes: 107 additions & 7 deletions cnc/gmachine.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from __future__ import division
import time

import cnc.logging_config as logging_config
from cnc import hal
from cnc.pulses import *
from cnc.coordinates import *
from cnc.heater import *
from cnc.enums import *


class GMachineException(Exception):
Expand All @@ -29,14 +30,18 @@ def __init__(self):
self._convertCoordinates = 0
self._absoluteCoordinates = 0
self._plane = None
self._fan_state = False
self._heaters = dict()
self.reset()
hal.init()

def release(self):
""" Return machine to original position and free all resources.
"""
self._spindle(0)
self.home()
self._spindle(0)
for h in self._heaters:
self._heaters[h].stop()
hal.deinit()

def reset(self):
Expand All @@ -55,6 +60,35 @@ def _spindle(self, spindle_speed):
hal.join()
hal.spindle_control(100.0 * spindle_speed / SPINDLE_MAX_RPM)

def _fan(self, state):
hal.fan_control(state)
self._fan_state = state

def _heat(self, heater, temperature, wait):
# check if sensor is ok
if heater == HEATER_EXTRUDER:
measure = hal.get_extruder_temperature
control = hal.extruder_heater_control
coefficients = EXTRUDER_PID
elif heater == HEATER_BED:
measure = hal.get_bed_temperature
control = hal.bed_heater_control
coefficients = BED_PID
else:
raise GMachineException("unknown heater")
try:
measure()
except (IOError, OSError):
raise GMachineException("can not measure temperature")
if heater in self._heaters:
self._heaters[heater].stop()
del self._heaters[heater]
if temperature != 0:
self._heaters[heater] = Heater(temperature, coefficients, measure,
control)
if wait:
self._heaters[heater].wait()

def __check_delta(self, delta):
pos = self._position + delta
if not pos.is_in_aabb(Coordinates(0.0, 0.0, 0.0, 0.0),
Expand Down Expand Up @@ -211,12 +245,37 @@ def plane(self):
"""
return self._plane

def fan_state(self):
""" Check if fan is on.
:return True if fan is on, False otherwise.
"""
return self._fan_state

def __get_target_temperature(self, heater):
if heater not in self._heaters:
return 0
return self._heaters[heater].target_temperature()

def extruder_target_temperature(self):
""" Return desired extruder temperature.
:return Temperature in Celsius, 0 if disabled.
"""
return self.__get_target_temperature(HEATER_EXTRUDER)

def bed_target_temperature(self):
""" Return desired bed temperature.
:return Temperature in Celsius, 0 if disabled.
"""
return self.__get_target_temperature(HEATER_BED)

def do_command(self, gcode):
""" Perform action.
:param gcode: GCode object which represent one gcode line
:return String if any answer require, None otherwise.
"""
if gcode is None:
return
return None
answer = None
logging.debug("got command " + str(gcode.params))
# read command
c = gcode.command()
Expand All @@ -232,15 +291,12 @@ def do_command(self, gcode):
self._convertCoordinates)
# coord = self._position + delta
velocity = gcode.get('F', self._velocity)
spindle_rpm = gcode.get('S', self._spindle_rpm)
pause = gcode.get('P', self._pause)
radius = gcode.radius(Coordinates(0.0, 0.0, 0.0, 0.0),
self._convertCoordinates)
# check parameters
if velocity <= 0 or velocity > STEPPER_MAX_VELOCITY_MM_PER_MIN:
raise GMachineException("bad feed speed")
if spindle_rpm < 0 or spindle_rpm > SPINDLE_MAX_RPM:
raise GMachineException("bad spindle speed")
if pause < 0:
raise GMachineException("bad delay")
# select command and run it
Expand Down Expand Up @@ -278,19 +334,63 @@ def do_command(self, gcode):
gcode.coordinates(Coordinates(0.0, 0.0, 0.0, 0.0),
self._convertCoordinates)
elif c == 'M3': # spindle on
spindle_rpm = gcode.get('S', self._spindle_rpm)
if spindle_rpm < 0 or spindle_rpm > SPINDLE_MAX_RPM:
raise GMachineException("bad spindle speed")
self._spindle(spindle_rpm)
self._spindle_rpm = spindle_rpm
elif c == 'M5': # spindle off
self._spindle(0)
elif c == 'M2' or c == 'M30': # program finish, reset everything.
self.reset()
# extruder and bed heaters control
elif c == 'M104' or c == 'M109' or c == 'M140' or c == 'M190':
if c == 'M104' or c == 'M109':
heater = HEATER_EXTRUDER
elif c == 'M140' or c == 'M190':
heater = HEATER_BED
else:
raise Exception("Unexpected heater command")
wait = c == 'M109' or c == 'M190'
if not gcode.has("S"):
raise GMachineException("temperature is not specified")
t = gcode.get('S', 0)
if ((heater == HEATER_EXTRUDER and t > EXTRUDER_MAX_TEMPERATURE) or
(heater == HEATER_BED and t > BED_MAX_TEMPERATURE) or
t < MIN_TEMPERATURE) and t != 0:
raise GMachineException("bad temperature")
self._heat(heater, t, wait)
elif c == 'M105': # get temperature
try:
et = hal.get_extruder_temperature()
except (IOError, OSError):
et = None
try:
bt = hal.get_bed_temperature()
except (IOError, OSError):
bt = None
if et is None and bt is None:
raise GMachineException("can not measure temperature")
answer = "E:{} B:{}".format(et, bt)
elif c == 'M106': # fan control
if gcode.get('S', 1) != 0:
self._fan(True)
else:
self._fan(False)
elif c == 'M107': # turn off fan
self._fan(False)
elif c == 'M111': # enable debug
logging_config.debug_enable()
elif c == 'M114': # get current position
hal.join()
p = self.position()
answer = "X:{} Y:{} Z:{} E:{}".format(p.x, p.y, p.z, p.e)
elif c is None: # command not specified(for example, just F was passed)
pass
else:
raise GMachineException("unknown command")
# save parameters on success
self._velocity = velocity
self._spindle_rpm = spindle_rpm
self._pause = pause
logging.debug("position {}".format(self._position))
return answer
52 changes: 49 additions & 3 deletions cnc/hal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,54 @@
# """ Initialize GPIO pins and machine itself, including calibration if
# needed. Do not return till all procedure is completed.
# """
# logging.info("initialize hal")
# do_something()
#
#
# def spindle_control(percent):
# """ Spindle control implementation.
# :param percent: Spindle speed in percent. 0 turns spindle off.
# :param percent: Spindle speed in percent 0..100. 0 turns spindle off.
# """
# logging.info("spindle control: {}%".format(percent))
# do_something()
#
#
# def fan_control(on_off):
# """
# Cooling fan control.
# :param on_off: boolean value if fan is enabled.
# """
# do_something()
#
#
# def extruder_heater_control(percent):
# """ Extruder heater control.
# :param percent: heater power in percent 0..100. 0 turns heater off.
# """
# do_something()
#
#
# def bed_heater_control(percent):
# """ Hot bed heater control.
# :param percent: heater power in percent 0..100. 0 turns heater off.
# """
# do_something()
#
#
# def get_extruder_temperature():
# """ Measure extruder temperature.
# Can raise OSError or IOError on any issue with sensor.
# :return: temperature in Celsius.
# """
# return measure()
#
#
# def get_bed_temperature():
# """ Measure bed temperature.
# Can raise OSError or IOError on any issue with sensor.
# :return: temperature in Celsius.
# """
# return measure()
#
#
# def move(generator):
# """ Move head to according pulses in PulseGenerator.
# :param generator: PulseGenerator object
Expand Down Expand Up @@ -49,6 +85,16 @@
raise NotImplementedError("hal.init() not implemented")
if 'spindle_control' not in locals():
raise NotImplementedError("hal.spindle_control() not implemented")
if 'fan_control' not in locals():
raise NotImplementedError("hal.fan_control() not implemented")
if 'extruder_heater_control' not in locals():
raise NotImplementedError("hal.extruder_heater_control() not implemented")
if 'bed_heater_control' not in locals():
raise NotImplementedError("hal.bed_heater_control() not implemented")
if 'get_extruder_temperature' not in locals():
raise NotImplementedError("hal.get_extruder_temperature() not implemented")
if 'get_bed_temperature' not in locals():
raise NotImplementedError("hal.get_bed_temperature() not implemented")
if 'move' not in locals():
raise NotImplementedError("hal.move() not implemented")
if 'join' not in locals():
Expand Down
Loading

0 comments on commit 5314694

Please sign in to comment.