diff --git a/config/example-corexz.cfg b/config/example-corexz.cfg new file mode 100644 index 00000000..a0cd9b85 --- /dev/null +++ b/config/example-corexz.cfg @@ -0,0 +1,81 @@ +# This file serves as documentation for config parameters of corexz +# style printers. One may copy and edit this file to configure a new +# corexz printer. Only parameters unique to corexz printers are +# described here - see the "example.cfg" file for description of common +# config parameters. + +# DO NOT COPY THIS FILE WITHOUT CAREFULLY READING AND UPDATING IT +# FIRST. Incorrectly configured parameters may cause damage. + +# The stepper_x section is used to describe the X axis as well as the +# stepper controlling the X+Z movement. +[stepper_x] +step_pin: ar54 +dir_pin: ar55 +enable_pin: !ar38 +step_distance: .01 +endstop_pin: ^ar3 +position_endstop: 0 +position_max: 200 +homing_speed: 50 + +[stepper_y] +step_pin: ar60 +dir_pin: ar61 +enable_pin: !ar56 +step_distance: .01 +endstop_pin: ^ar14 +position_endstop: 0 +position_max: 200 +homing_speed: 50 + +# The stepper_z section is used to describe the Z axis as well as the +# stepper controlling the X-Z movement. +[stepper_z] +step_pin: ar46 +dir_pin: ar48 +enable_pin: !ar62 +step_distance: .0025 +endstop_pin: ^ar18 +position_endstop: 0.5 +position_max: 200 + +[extruder] +step_pin: ar26 +dir_pin: ar28 +enable_pin: !ar24 +step_distance: .0022 +nozzle_diameter: 0.400 +filament_diameter: 1.750 +heater_pin: ar10 +sensor_type: ATC Semitec 104GT-2 +sensor_pin: analog13 +control: pid +pid_Kp: 22.2 +pid_Ki: 1.08 +pid_Kd: 114 +min_temp: 0 +max_temp: 250 + +[heater_bed] +heater_pin: ar8 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: analog14 +control: watermark +min_temp: 0 +max_temp: 130 + +[fan] +pin: ar9 + +[mcu] +serial: /dev/ttyACM0 +pin_map: arduino + +[printer] +kinematics: corexz +# This option must be "corexz" for corexz printers. +max_velocity: 300 +max_accel: 3000 +max_z_velocity: 50 +max_z_accel: 30 diff --git a/klippy/chelper/__init__.py b/klippy/chelper/__init__.py index d87c0b31..b29b8e68 100644 --- a/klippy/chelper/__init__.py +++ b/klippy/chelper/__init__.py @@ -16,8 +16,9 @@ COMPILE_CMD = ("gcc -Wall -g -O2 -shared -fPIC" " -o %s %s") SOURCE_FILES = [ 'pyhelper.c', 'serialqueue.c', 'stepcompress.c', 'itersolve.c', 'trapq.c', - 'kin_cartesian.c', 'kin_corexy.c', 'kin_delta.c', 'kin_polar.c', - 'kin_rotary_delta.c', 'kin_winch.c', 'kin_extruder.c', 'kin_shaper.c', + 'kin_cartesian.c', 'kin_corexy.c', 'kin_corexz.c', 'kin_delta.c', + 'kin_polar.c', 'kin_rotary_delta.c', 'kin_winch.c', 'kin_extruder.c', + 'kin_shaper.c', ] DEST_LIB = "c_helper.so" OTHER_FILES = [ @@ -78,6 +79,10 @@ defs_kin_corexy = """ struct stepper_kinematics *corexy_stepper_alloc(char type); """ +defs_kin_corexz = """ + struct stepper_kinematics *corexz_stepper_alloc(char type); +""" + defs_kin_delta = """ struct stepper_kinematics *delta_stepper_alloc(double arm2 , double tower_x, double tower_y); @@ -165,11 +170,10 @@ defs_std = """ """ defs_all = [ - defs_pyhelper, defs_serialqueue, defs_std, - defs_stepcompress, defs_itersolve, defs_trapq, - defs_kin_cartesian, defs_kin_corexy, defs_kin_delta, defs_kin_polar, - defs_kin_rotary_delta, defs_kin_winch, defs_kin_extruder, - defs_kin_shaper, + defs_pyhelper, defs_serialqueue, defs_std, defs_stepcompress, + defs_itersolve, defs_trapq, defs_kin_cartesian, defs_kin_corexy, + defs_kin_corexz, defs_kin_delta, defs_kin_polar, defs_kin_rotary_delta, + defs_kin_winch, defs_kin_extruder, defs_kin_shaper, ] # Return the list of file modification times diff --git a/klippy/chelper/kin_corexz.c b/klippy/chelper/kin_corexz.c new file mode 100644 index 00000000..320dc239 --- /dev/null +++ b/klippy/chelper/kin_corexz.c @@ -0,0 +1,40 @@ +// CoreXZ kinematics stepper pulse time generation +// +// Copyright (C) 2020 Maks Zolin +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include // malloc +#include // memset +#include "compiler.h" // __visible +#include "itersolve.h" // struct stepper_kinematics +#include "trapq.h" // move_get_coord + +static double +corexz_stepper_plus_calc_position(struct stepper_kinematics *sk, struct move *m + , double move_time) +{ + struct coord c = move_get_coord(m, move_time); + return c.x + c.z; +} + +static double +corexz_stepper_minus_calc_position(struct stepper_kinematics *sk, struct move *m + , double move_time) +{ + struct coord c = move_get_coord(m, move_time); + return c.x - c.z; +} + +struct stepper_kinematics * __visible +corexz_stepper_alloc(char type) +{ + struct stepper_kinematics *sk = malloc(sizeof(*sk)); + memset(sk, 0, sizeof(*sk)); + if (type == '+') + sk->calc_position_cb = corexz_stepper_plus_calc_position; + else if (type == '-') + sk->calc_position_cb = corexz_stepper_minus_calc_position; + sk->active_flags = AF_X | AF_Z; + return sk; +} diff --git a/klippy/kinematics/corexz.py b/klippy/kinematics/corexz.py new file mode 100644 index 00000000..8addecf7 --- /dev/null +++ b/klippy/kinematics/corexz.py @@ -0,0 +1,101 @@ +# Code for handling the kinematics of corexz robots +# +# Copyright (C) 2020 Maks Zolin +# +# This file may be distributed under the terms of the GNU GPLv3 license. +import logging, math +import stepper, homing + +class CoreXZKinematics: + def __init__(self, toolhead, config): + # Setup axis rails + self.rails = [ stepper.PrinterRail(config.getsection('stepper_x')), + stepper.PrinterRail(config.getsection('stepper_y')), + stepper.PrinterRail(config.getsection('stepper_z')) ] + self.rails[0].get_endstops()[0][0].add_stepper( + self.rails[2].get_steppers()[0]) + self.rails[2].get_endstops()[0][0].add_stepper( + self.rails[0].get_steppers()[0]) + self.rails[0].setup_itersolve('corexz_stepper_alloc', '+') + self.rails[1].setup_itersolve('cartesian_stepper_alloc', 'y') + self.rails[2].setup_itersolve('corexz_stepper_alloc', '-') + for s in self.get_steppers(): + s.set_trapq(toolhead.get_trapq()) + toolhead.register_step_generator(s.generate_steps) + config.get_printer().register_event_handler("stepper_enable:motor_off", + self._motor_off) + # Setup boundary checks + max_velocity, max_accel = toolhead.get_max_velocity() + self.max_z_velocity = config.getfloat( + 'max_z_velocity', max_velocity, above=0., maxval=max_velocity) + self.max_z_accel = config.getfloat( + 'max_z_accel', max_accel, above=0., maxval=max_accel) + self.limits = [(1.0, -1.0)] * 3 + # Setup stepper max halt velocity + max_halt_velocity = toolhead.get_max_axis_halt() + max_xy_halt_velocity = max_halt_velocity * math.sqrt(2.) + max_xy_accel = max_accel * math.sqrt(2.) + self.rails[0].set_max_jerk(max_xy_halt_velocity, max_xy_accel) + self.rails[1].set_max_jerk(max_xy_halt_velocity, max_xy_accel) + self.rails[2].set_max_jerk(max_xy_halt_velocity, max_xy_accel) + def get_steppers(self): + return [s for rail in self.rails for s in rail.get_steppers()] + def calc_tag_position(self): + pos = [rail.get_tag_position() for rail in self.rails] + return [0.5 * (pos[0] + pos[2]), pos[1], 0.5 * (pos[0] - pos[2])] + def set_position(self, newpos, homing_axes): + for i, rail in enumerate(self.rails): + rail.set_position(newpos) + if i in homing_axes: + self.limits[i] = rail.get_range() + def note_z_not_homed(self): + # Helper for Safe Z Home + self.limits[2] = (1.0, -1.0) + def home(self, homing_state): + # Each axis is homed independently and in order + for axis in homing_state.get_axes(): + rail = self.rails[axis] + # Determine movement + position_min, position_max = rail.get_range() + hi = rail.get_homing_info() + homepos = [None, None, None, None] + homepos[axis] = hi.position_endstop + forcepos = list(homepos) + if hi.positive_dir: + forcepos[axis] -= 1.5 * (hi.position_endstop - position_min) + else: + forcepos[axis] += 1.5 * (position_max - hi.position_endstop) + # Perform homing + homing_state.home_rails([rail], forcepos, homepos) + def _motor_off(self, print_time): + self.limits = [(1.0, -1.0)] * 3 + def _check_endstops(self, move): + end_pos = move.end_pos + for i in (0, 1, 2): + if (move.axes_d[i] + and (end_pos[i] < self.limits[i][0] + or end_pos[i] > self.limits[i][1])): + if self.limits[i][0] > self.limits[i][1]: + raise homing.EndstopMoveError( + end_pos, "Must home axis first") + raise homing.EndstopMoveError(end_pos) + def check_move(self, move): + limits = self.limits + xpos, ypos = move.end_pos[:2] + if (xpos < limits[0][0] or xpos > limits[0][1] + or ypos < limits[1][0] or ypos > limits[1][1]): + self._check_endstops(move) + if not move.axes_d[2]: + # Normal XY move - use defaults + return + # Move with Z - update velocity and accel for slower Z axis + self._check_endstops(move) + z_ratio = move.move_d / abs(move.axes_d[2]) + move.limit_speed( + self.max_z_velocity * z_ratio, self.max_z_accel * z_ratio) + def get_status(self, eventtime): + axes = [a for a, (l, h) in zip("xyz", self.limits) if l <= h] + return {'homed_axes': "".join(axes)} + +def load_kinematics(toolhead, config): + return CoreXZKinematics(toolhead, config) diff --git a/test/klippy/printers.test b/test/klippy/printers.test index b8c5f441..c77e720b 100644 --- a/test/klippy/printers.test +++ b/test/klippy/printers.test @@ -5,6 +5,7 @@ GCODE move.gcode DICTIONARY atmega2560.dict CONFIG ../../config/example.cfg CONFIG ../../config/example-corexy.cfg +CONFIG ../../config/example-corexz.cfg CONFIG ../../config/example-delta.cfg CONFIG ../../config/example-rotary-delta.cfg CONFIG ../../config/example-winch.cfg