1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# Support for duplication and mirroring modes for IDEX printers
#
# Copyright (C) 2021 Fabrice Gallet <tircown@gmail.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import math
import chelper
class DualCarriages:
def __init__(self, printer, rail_0, rail_1, axis):
self.printer = printer
self.axis = axis
self.dc = (rail_0, rail_1)
self.saved_state = None
self.printer.add_object('dual_carriage', self)
gcode = self.printer.lookup_object('gcode')
gcode.register_command(
'SET_DUAL_CARRIAGE', self.cmd_SET_DUAL_CARRIAGE,
desc=self.cmd_SET_DUAL_CARRIAGE_help)
def toggle_active_dc_rail(self, index):
toolhead = self.printer.lookup_object('toolhead')
toolhead.flush_step_generation()
pos = toolhead.get_position()
kin = toolhead.get_kinematics()
for i, dc in enumerate(self.dc):
dc_rail = dc.get_rail()
if i != index:
if dc.is_active():
dc.inactivate(pos)
kin.override_rail(3, dc_rail)
elif dc.is_active() is False:
newpos = pos[:self.axis] + [dc.axis_position] \
+ pos[self.axis+1:]
dc.activate(newpos)
kin.override_rail(self.axis, dc_rail)
toolhead.set_position(newpos)
kin.update_limits(self.axis, dc_rail.get_range())
def get_status(self, eventtime=None):
dc0, dc1 = self.dc
if (dc0.is_active() is True):
return { 'mode': 'FULL_CONTROL', 'active_carriage': 'CARRIAGE_0' }
else:
return { 'mode': 'FULL_CONTROL', 'active_carriage': 'CARRIAGE_1' }
def save_idex_state(self):
dc0, dc1 = self.dc
if (dc0.is_active() is True):
mode, active_carriage = ('FULL_CONTROL', 'CARRIAGE_0')
else:
mode, active_carriage = ('FULL_CONTROL', 'CARRIAGE_1')
self.saved_state = {
'mode': mode,
'active_carriage': active_carriage,
'axis_positions': (dc0.axis_position, dc1.axis_position)
}
def restore_idex_state(self):
if self.saved_state is not None:
# set carriage 0 active
if (self.saved_state['active_carriage'] == 'CARRIAGE_0'
and self.dc[0].is_active() is False):
self.toggle_active_dc_rail(0)
# set carriage 1 active
elif (self.saved_state['active_carriage'] == 'CARRIAGE_1'
and self.dc[1].is_active() is False):
self.toggle_active_dc_rail(1)
cmd_SET_DUAL_CARRIAGE_help = "Set which carriage is active"
def cmd_SET_DUAL_CARRIAGE(self, gcmd):
index = gcmd.get_int('CARRIAGE', minval=0, maxval=1)
if (not(self.dc[0].is_active() == self.dc[1].is_active() == True)
and self.dc[index].is_active() is False):
self.toggle_active_dc_rail(index)
class DualCarriagesRail:
ACTIVE=1
INACTIVE=2
def __init__(self, printer, rail, axis, active, stepper_alloc_active,
stepper_alloc_inactive=None):
self.printer = printer
self.rail = rail
self.axis = axis
self.status = (self.INACTIVE, self.ACTIVE)[active]
self.stepper_alloc_active = stepper_alloc_active
self.stepper_alloc_inactive = stepper_alloc_inactive
self.axis_position = -1
self.stepper_active_sk = {}
self.stepper_inactive_sk = {}
for s in rail.get_steppers():
self._save_sk(self.status, s, s.get_stepper_kinematics())
def _alloc_sk(self, alloc_func, *params):
ffi_main, ffi_lib = chelper.get_ffi()
return ffi_main.gc(getattr(ffi_lib, alloc_func)(*params), ffi_lib.free)
def _get_sk(self, status, stepper):
sk = None
if status == self.ACTIVE:
sk = self.stepper_active_sk.get(stepper, None)
if sk is None and self.stepper_alloc_active:
sk = self._alloc_sk(*self.stepper_alloc_active)
self._save_sk(status, stepper, sk)
elif status == self.INACTIVE:
sk = self.stepper_inactive_sk.get(stepper, None)
if sk is None and self.stepper_alloc_inactive:
sk = self._alloc_sk(*self.stepper_alloc_inactive)
self._save_sk(status, stepper, sk)
return sk
def _save_sk(self, status, stepper, sk):
if status == self.ACTIVE:
self.stepper_active_sk[stepper] = sk
elif status == self.INACTIVE:
self.stepper_inactive_sk[stepper] = sk
def _update_stepper_alloc(self, position, active=True):
toolhead = self.printer.lookup_object('toolhead')
self.axis_position = position[self.axis]
self.rail.set_trapq(None)
old_status = self.status
self.status = (self.INACTIVE, self.ACTIVE)[active]
for s in self.rail.get_steppers():
sk = self._get_sk(self.status, s)
if sk is None:
return
old_sk = s.set_stepper_kinematics(sk)
self._save_sk(old_status, s, old_sk)
self.rail.set_position(position)
self.rail.set_trapq(toolhead.get_trapq())
def get_rail(self):
return self.rail
def is_active(self):
return self.status == self.ACTIVE
def activate(self, position):
self._update_stepper_alloc(position, active=True)
def inactivate(self, position):
self._update_stepper_alloc(position, active=False)
|