mirror of
https://github.com/sinseman44/PyCNC.git
synced 2026-01-11 02:30:05 +00:00
m84 real implementation, refactoring: mostly line width
This commit is contained in:
@@ -32,8 +32,9 @@ 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, M104, M105, M106, M107, M109, M114, M140, M190 are supported.
|
||||
Commands can be easily added, see [gmachine.py](./cnc/gmachine.py) file.
|
||||
M2, M3, M5, M30, M84, 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.
|
||||
|
||||
@@ -52,6 +52,8 @@ BED_PID = {"P": 5.06820175723,
|
||||
# -----------------------------------------------------------------------------
|
||||
# Pins configuration.
|
||||
|
||||
# Enable pin for all steppers, low level is enabled.
|
||||
STEPPERS_ENABLE_PIN = 26
|
||||
STEPPER_STEP_PIN_X = 16
|
||||
STEPPER_STEP_PIN_Y = 20
|
||||
STEPPER_STEP_PIN_Z = 21
|
||||
|
||||
@@ -220,8 +220,8 @@ class GMachine(object):
|
||||
logging.info("Moving circularly {} {} {} with radius {}"
|
||||
" and velocity {}".format(self._plane, circle_end,
|
||||
direction, radius, velocity))
|
||||
gen = PulseGeneratorCircular(circle_end, radius, self._plane, direction,
|
||||
velocity)
|
||||
gen = PulseGeneratorCircular(circle_end, radius, self._plane,
|
||||
direction, velocity)
|
||||
self.__check_velocity(gen.max_velocity())
|
||||
# if finish coords is not on circle, move some distance linearly
|
||||
linear_delta = delta - circle_end
|
||||
@@ -411,6 +411,8 @@ class GMachine(object):
|
||||
self._spindle(0)
|
||||
elif c == 'M2' or c == 'M30': # program finish, reset everything.
|
||||
self.reset()
|
||||
elif c == 'M84': # disable motors
|
||||
hal.disable_steppers()
|
||||
# extruder and bed heaters control
|
||||
elif c == 'M104' or c == 'M109' or c == 'M140' or c == 'M190':
|
||||
if c == 'M104' or c == 'M109':
|
||||
@@ -453,7 +455,7 @@ class GMachine(object):
|
||||
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)
|
||||
elif c is None: # command not specified(ie just F was passed)
|
||||
pass
|
||||
# commands below are added just for compatibility
|
||||
elif c == 'M82': # absolute mode for extruder
|
||||
@@ -462,8 +464,6 @@ class GMachine(object):
|
||||
elif c == 'M83': # relative mode for extruder
|
||||
if self._absoluteCoordinates:
|
||||
raise GMachineException("Not supported, use G90/G91")
|
||||
elif c == 'M84': # disable motors
|
||||
pass # do not do anything
|
||||
else:
|
||||
raise GMachineException("unknown command")
|
||||
# save parameters on success
|
||||
|
||||
10
cnc/hal.py
10
cnc/hal.py
@@ -51,6 +51,13 @@
|
||||
# """
|
||||
# return measure()
|
||||
#
|
||||
#
|
||||
# def disable_steppers():
|
||||
# """ Disable all steppers until any movement occurs.
|
||||
# """
|
||||
# do_something()
|
||||
#
|
||||
#
|
||||
# def calibrate(x, y, z):
|
||||
# """ Move head to home position till end stop switch will be triggered.
|
||||
# Do not return till all procedures are completed.
|
||||
@@ -61,6 +68,7 @@
|
||||
# """
|
||||
# return do_something()
|
||||
#
|
||||
#
|
||||
# def move(generator):
|
||||
# """ Move head to according pulses in PulseGenerator.
|
||||
# :param generator: PulseGenerator object
|
||||
@@ -103,6 +111,8 @@ 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 'disable_steppers' not in locals():
|
||||
raise NotImplementedError("hal.disable_steppers() not implemented")
|
||||
if 'calibrate' not in locals():
|
||||
raise NotImplementedError("hal.calibrate() not implemented")
|
||||
if 'move' not in locals():
|
||||
|
||||
@@ -35,10 +35,12 @@ def init():
|
||||
gpio.init(FAN_PIN, rpgpio.GPIO.MODE_OUTPUT)
|
||||
gpio.init(EXTRUDER_HEATER_PIN, rpgpio.GPIO.MODE_OUTPUT)
|
||||
gpio.init(BED_HEATER_PIN, rpgpio.GPIO.MODE_OUTPUT)
|
||||
gpio.init(STEPPERS_ENABLE_PIN, rpgpio.GPIO.MODE_OUTPUT)
|
||||
gpio.clear(SPINDLE_PWM_PIN)
|
||||
gpio.clear(FAN_PIN)
|
||||
gpio.clear(EXTRUDER_HEATER_PIN)
|
||||
gpio.clear(BED_HEATER_PIN)
|
||||
gpio.clear(STEPPERS_ENABLE_PIN)
|
||||
|
||||
|
||||
def spindle_control(percent):
|
||||
@@ -99,6 +101,13 @@ def get_bed_temperature():
|
||||
return thermistor.get_temperature(BED_TEMPERATURE_SENSOR_CHANNEL)
|
||||
|
||||
|
||||
def disable_steppers():
|
||||
""" Disable all steppers until any movement occurs.
|
||||
"""
|
||||
logging.info("disable steppers")
|
||||
gpio.set(STEPPERS_ENABLE_PIN)
|
||||
|
||||
|
||||
def __calibrate_private(x, y, z, invert):
|
||||
if invert:
|
||||
stepper_inverted_x = not STEPPER_INVERTED_X
|
||||
@@ -190,6 +199,8 @@ def calibrate(x, y, z):
|
||||
:param z: boolean, True to calibrate Z axis.
|
||||
:return: boolean, True if all specified end stops were triggered.
|
||||
"""
|
||||
# enable steppers
|
||||
gpio.clear(STEPPERS_ENABLE_PIN)
|
||||
logging.info("hal calibrate, x={}, y={}, z={}".format(x, y, z))
|
||||
if not __calibrate_private(x, y, z, True): # move from endstop switch
|
||||
return False
|
||||
@@ -206,6 +217,8 @@ def move(generator):
|
||||
# moving. In this case machine would safely paused between commands until
|
||||
# calculation is done.
|
||||
|
||||
# enable steppers
|
||||
gpio.clear(STEPPERS_ENABLE_PIN)
|
||||
# 4 control blocks per 32 bytes
|
||||
bytes_per_iter = 4 * dma.control_block_size()
|
||||
# prepare and run dma
|
||||
@@ -309,6 +322,7 @@ def deinit():
|
||||
""" De-initialize hardware.
|
||||
"""
|
||||
join()
|
||||
disable_steppers()
|
||||
pwm.remove_all()
|
||||
gpio.clear(SPINDLE_PWM_PIN)
|
||||
gpio.clear(FAN_PIN)
|
||||
|
||||
@@ -15,8 +15,8 @@ class GPIO(object):
|
||||
|
||||
def __init__(self):
|
||||
""" Create object which can control GPIO.
|
||||
This class writes directly to CPU registers and doesn't use any libs
|
||||
or kernel modules.
|
||||
This class writes directly to CPU registers and doesn't use any
|
||||
libs or kernel modules.
|
||||
"""
|
||||
self._mem = PhysicalMemory(PERI_BASE + GPIO_REGISTER_BASE)
|
||||
|
||||
@@ -191,7 +191,7 @@ class DMAGPIO(DMAProto):
|
||||
self._phys_memory.write_int(self.__current_address + 20
|
||||
- self._DMA_CONTROL_BLOCK_SIZE, 0)
|
||||
logging.info("DMA took {}MB of memory".
|
||||
format(round(self.__current_address / 1024.0 / 1024.0, 2)))
|
||||
format(round(self.__current_address / 1048576.0, 2)))
|
||||
|
||||
def run_stream(self):
|
||||
""" Run DMA module in stream mode, i.e. does'n finalize last block
|
||||
@@ -199,18 +199,19 @@ class DMAGPIO(DMAProto):
|
||||
"""
|
||||
# configure PWM hardware module which will clocks DMA
|
||||
self._pwm.write_int(PWM_CTL, 0)
|
||||
self._clock.write_int(CM_PWM_CNTL, CM_PASSWORD | CM_SRC_PLLD) # disable
|
||||
# disable
|
||||
self._clock.write_int(CM_PWM_CNTL, CM_PASSWORD | CM_SRC_PLLD)
|
||||
while (self._clock.read_int(CM_PWM_CNTL) & CM_CNTL_BUSY) != 0:
|
||||
time.sleep(0.00001) # 10 us, wait until BUSY bit is clear
|
||||
self._clock.write_int(CM_PWM_DIV,
|
||||
CM_PASSWORD | CM_DIV_VALUE(5)) # 100MHz
|
||||
# configure, 100 MHz
|
||||
self._clock.write_int(CM_PWM_DIV, CM_PASSWORD | CM_DIV_VALUE(5))
|
||||
self._clock.write_int(CM_PWM_CNTL,
|
||||
CM_PASSWORD | CM_SRC_PLLD | CM_CNTL_ENABLE)
|
||||
|
||||
self._pwm.write_int(PWM_RNG1, 100)
|
||||
self._pwm.write_int(PWM_DMAC, PWM_DMAC_ENAB
|
||||
| PWM_DMAC_PANIC(15) | PWM_DMAC_DREQ(15))
|
||||
self._pwm.write_int(PWM_DMAC, PWM_DMAC_ENAB | PWM_DMAC_PANIC(15)
|
||||
| PWM_DMAC_DREQ(15))
|
||||
self._pwm.write_int(PWM_CTL, PWM_CTL_CLRF)
|
||||
# enable
|
||||
self._pwm.write_int(PWM_CTL, PWM_CTL_USEF1 | PWM_CTL_PWEN1)
|
||||
super(DMAGPIO, self)._run_dma()
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ def get_bed_temperature():
|
||||
return BED_MAX_TEMPERATURE * 0.999
|
||||
|
||||
|
||||
def disable_steppers():
|
||||
""" Disable all steppers until any movement occurs.
|
||||
"""
|
||||
logging.info("hal disable steppers")
|
||||
|
||||
|
||||
def calibrate(x, y, z):
|
||||
""" Move head to home position till end stop switch will be triggered.
|
||||
Do not return till all procedures are completed.
|
||||
|
||||
@@ -61,8 +61,8 @@ class Heater(threading.Thread):
|
||||
last_error = time.time()
|
||||
else:
|
||||
if time.time() - last_error > self.SENSOR_TIMEOUT_S:
|
||||
logging.critical("No data from temperature sensor. Stop"
|
||||
" heating.")
|
||||
logging.critical("No data from temperature sensor."
|
||||
" Stop heating.")
|
||||
break
|
||||
continue
|
||||
last_error = None
|
||||
@@ -87,8 +87,8 @@ class Heater(threading.Thread):
|
||||
i = 0
|
||||
while not self._pid.is_fixed():
|
||||
if i % 8 == 0:
|
||||
logging.info("Heating... current temperature {} C, power {}%"
|
||||
.format(self._measure(), int(self._current_power)))
|
||||
logging.info("Heating... current temperature {} C, power {}%".
|
||||
format(self._measure(), int(self._current_power)))
|
||||
i = 0
|
||||
i += 1
|
||||
time.sleep(0.25)
|
||||
|
||||
@@ -609,9 +609,10 @@ class PulseGeneratorCircular(PulseGenerator):
|
||||
def __circular_a(self, i, pulses_per_mm):
|
||||
if i >= self._iterations_a:
|
||||
return self._dir_a, None
|
||||
a, direction, side = self.__circular_helper(self._start_a_pulses, i + 1,
|
||||
self._radius_a_pulses,
|
||||
self._side_a, self._dir_a)
|
||||
a, direction, side = \
|
||||
self.__circular_helper(self._start_a_pulses, i + 1,
|
||||
self._radius_a_pulses,
|
||||
self._side_a, self._dir_a)
|
||||
a /= pulses_per_mm
|
||||
# first and last item can be slightly out of bound due float precision
|
||||
if i + 1 == self._iterations_a:
|
||||
@@ -624,9 +625,10 @@ class PulseGeneratorCircular(PulseGenerator):
|
||||
def __circular_b(self, i, pulses_per_mm):
|
||||
if i >= self._iterations_b:
|
||||
return self._dir_b, None
|
||||
b, direction, side = self.__circular_helper(self._start_b_pulses, i + 1,
|
||||
self._radius_b_pulses,
|
||||
self._side_b, self._dir_b)
|
||||
b, direction, side = \
|
||||
self.__circular_helper(self._start_b_pulses, i + 1,
|
||||
self._radius_b_pulses,
|
||||
self._side_b, self._dir_b)
|
||||
b /= pulses_per_mm
|
||||
# first and last item can be slightly out of bound due float precision
|
||||
if i + 1 == self._iterations_b:
|
||||
|
||||
@@ -78,7 +78,8 @@ class TestGMachine(unittest.TestCase):
|
||||
self.assertRaises(GMachineException,
|
||||
m.do_command, GCode.parse_line("G1X1F-1"))
|
||||
cl = "G1X1F" + str(MIN_VELOCITY_MM_PER_MIN - 0.0000001)
|
||||
self.assertRaises(GMachineException, m.do_command, GCode.parse_line(cl))
|
||||
self.assertRaises(GMachineException, m.do_command,
|
||||
GCode.parse_line(cl))
|
||||
m.do_command(GCode.parse_line("G1X100F"
|
||||
+ str(MAX_VELOCITY_MM_PER_MIN_X)))
|
||||
m.do_command(GCode.parse_line("G1Y100F"
|
||||
@@ -120,7 +121,8 @@ class TestGMachine(unittest.TestCase):
|
||||
m.do_command, GCode.parse_line("G2X99999999Y99999999"
|
||||
"I1J1"))
|
||||
self.assertRaises(GMachineException,
|
||||
m.do_command, GCode.parse_line("G2X2Y2Z99999999I1J1"))
|
||||
m.do_command,
|
||||
GCode.parse_line("G2X2Y2Z99999999I1J1"))
|
||||
self.assertEqual(m.position(), Coordinates(0, 0, 0, 0))
|
||||
self.assertRaises(GMachineException,
|
||||
m.do_command, GCode.parse_line("G2X4Y4I2J2"))
|
||||
@@ -250,9 +252,9 @@ class TestGMachine(unittest.TestCase):
|
||||
self.assertEqual(m.extruder_target_temperature(), 0)
|
||||
self.assertRaises(GMachineException, m.do_command,
|
||||
GCode.parse_line("M104S"+str(MIN_TEMPERATURE - 1)))
|
||||
et = EXTRUDER_MAX_TEMPERATURE + 1
|
||||
self.assertRaises(GMachineException, m.do_command,
|
||||
GCode.parse_line("M109S"
|
||||
+ str(EXTRUDER_MAX_TEMPERATURE + 1)))
|
||||
GCode.parse_line("M109S" + str(et)))
|
||||
self.assertRaises(GMachineException, m.do_command,
|
||||
GCode.parse_line("M109"))
|
||||
|
||||
|
||||
@@ -64,8 +64,8 @@ class TestHeater(unittest.TestCase):
|
||||
def test_fail(self):
|
||||
# check if heater will not fix with incorrect temperature
|
||||
self._control_counter = 0
|
||||
he = Heater(self._target_temp, EXTRUDER_PID, self.__get_bad_temperature,
|
||||
self.__control)
|
||||
he = Heater(self._target_temp, EXTRUDER_PID,
|
||||
self.__get_bad_temperature, self.__control)
|
||||
j = 0
|
||||
while self._control_counter < 10:
|
||||
time.sleep(0.01)
|
||||
|
||||
@@ -10,8 +10,8 @@ from cnc.hal_raspberry import hal
|
||||
|
||||
|
||||
"""
|
||||
This executable module is looking for heating and cooling transfer coefficients.
|
||||
Can be ran only on real hardware.
|
||||
This executable module is looking for heating and cooling transfer
|
||||
coefficients. Can be ran only on real hardware.
|
||||
"""
|
||||
|
||||
# change settings below for your hardware/environment
|
||||
|
||||
Reference in New Issue
Block a user