m84 real implementation, refactoring: mostly line width

This commit is contained in:
Nikolay Khabarov
2017-07-09 04:12:31 +03:00
parent 129d26ed5e
commit f549801bdd
12 changed files with 72 additions and 34 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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():

View File

@@ -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)

View File

@@ -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()

View File

@@ -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.

View File

@@ -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)

View File

@@ -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:

View File

@@ -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"))

View File

@@ -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)

View File

@@ -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