2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# Code for handling the kinematics of polar robots
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#
							 | 
						
					
						
							
								
									
										
										
										
											2021-01-08 11:52:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								# Copyright (C) 2018-2021  Kevin O'Connor <kevin@koconnor.net>
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# This file may be distributed under the terms of the GNU GPLv3 license.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import logging, math
							 | 
						
					
						
							
								
									
										
										
										
											2021-01-08 11:52:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import stepper
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								class PolarKinematics:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def __init__(self, toolhead, config):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Setup axis steppers
							 | 
						
					
						
							
								
									
										
										
										
											2019-12-04 18:42:59 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        stepper_bed = stepper.PrinterStepper(config.getsection('stepper_bed'),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                             units_in_radians=True)
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        rail_arm = stepper.PrinterRail(config.getsection('stepper_arm'))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        rail_z = stepper.LookupMultiRail(config.getsection('stepper_z'))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        stepper_bed.setup_itersolve('polar_stepper_alloc', 'a')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        rail_arm.setup_itersolve('polar_stepper_alloc', 'r')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        rail_z.setup_itersolve('cartesian_stepper_alloc', 'z')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.rails = [rail_arm, rail_z]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.steppers = [stepper_bed] + [ s for r in self.rails
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                          for s in r.get_steppers() ]
							 | 
						
					
						
							
								
									
										
										
										
											2019-10-28 23:13:58 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        for s in self.get_steppers():
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            s.set_trapq(toolhead.get_trapq())
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-07 10:59:35 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            toolhead.register_step_generator(s.generate_steps)
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-12 11:41:41 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        config.get_printer().register_event_handler("stepper_enable:motor_off",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                                    self._motor_off)
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # 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)
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-05 05:13:09 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.limit_z = (1.0, -1.0)
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.limit_xy2 = -1.
							 | 
						
					
						
							
								
									
										
										
										
											2021-01-08 11:52:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        max_xy = self.rails[0].get_range()[1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        min_z, max_z = self.rails[1].get_range()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.axes_min = toolhead.Coord(-max_xy, -max_xy, min_z, 0.)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.axes_max = toolhead.Coord(max_xy, max_xy, max_z, 0.)
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-13 21:39:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def get_steppers(self):
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return list(self.steppers)
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-13 17:59:40 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def calc_tag_position(self):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        bed_angle = self.steppers[0].get_tag_position()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        arm_pos = self.rails[0].get_tag_position()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        z_pos = self.rails[1].get_tag_position()
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return [math.cos(bed_angle) * arm_pos, math.sin(bed_angle) * arm_pos,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                z_pos]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def set_position(self, newpos, homing_axes):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for s in self.steppers:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            s.set_position(newpos)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if 2 in homing_axes:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.limit_z = self.rails[1].get_range()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if 0 in homing_axes and 1 in homing_axes:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self.limit_xy2 = self.rails[0].get_range()[1]**2
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-01 23:00:41 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def note_z_not_homed(self):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Helper for Safe Z Home
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.limit_z = (1.0, -1.0)
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def _home_axis(self, homing_state, axis, rail):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Determine movement
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        position_min, position_max = rail.get_range()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        hi = rail.get_homing_info()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        homepos = [None, None, None, None]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        homepos[axis] = hi.position_endstop
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if axis == 0:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            homepos[1] = 0.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        forcepos = list(homepos)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if hi.positive_dir:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            forcepos[axis] -= hi.position_endstop - position_min
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            forcepos[axis] += position_max - hi.position_endstop
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Perform homing
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-27 13:11:58 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        homing_state.home_rails([rail], forcepos, homepos)
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def home(self, homing_state):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Always home XY together
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        homing_axes = homing_state.get_axes()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        home_xy = 0 in homing_axes or 1 in homing_axes
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        home_z = 2 in homing_axes
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        updated_axes = []
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if home_xy:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            updated_axes = [0, 1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if home_z:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            updated_axes.append(2)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        homing_state.set_axes(updated_axes)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Do actual homing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if home_xy:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self._home_axis(homing_state, 0, self.rails[0])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if home_z:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            self._home_axis(homing_state, 2, self.rails[1])
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-12 11:41:41 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def _motor_off(self, print_time):
							 | 
						
					
						
							
								
									
										
										
										
											2020-08-05 05:13:09 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        self.limit_z = (1.0, -1.0)
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        self.limit_xy2 = -1.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    def check_move(self, move):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        end_pos = move.end_pos
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        xy2 = end_pos[0]**2 + end_pos[1]**2
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if xy2 > self.limit_xy2:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if self.limit_xy2 < 0.:
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 16:22:54 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                raise move.move_error("Must home axis first")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            raise move.move_error()
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if move.axes_d[2]:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if end_pos[2] < self.limit_z[0] or end_pos[2] > self.limit_z[1]:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if self.limit_z[0] > self.limit_z[1]:
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 16:22:54 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    raise move.move_error("Must home axis first")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                raise move.move_error()
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            # Move with Z - update velocity and accel for slower Z axis
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            z_ratio = move.move_d / abs(move.axes_d[2])
							 | 
						
					
						
							
								
									
										
										
										
											2020-09-03 16:22:54 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            move.limit_speed(self.max_z_velocity * z_ratio,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                             self.max_z_accel * z_ratio)
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-24 19:16:21 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    def get_status(self, eventtime):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        xy_home = "xy" if self.limit_xy2 >= 0. else ""
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        z_home = "z" if self.limit_z[0] <= self.limit_z[1] else ""
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-28 00:37:32 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'homed_axes': xy_home + z_home,
							 | 
						
					
						
							
								
									
										
										
										
											2021-01-08 11:52:28 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'axis_minimum': self.axes_min,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'axis_maximum': self.axes_max,
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-28 00:37:32 +02:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2018-08-23 14:21:58 -04:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def load_kinematics(toolhead, config):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return PolarKinematics(toolhead, config)
							 |