File: linuxcnc_util.py

package info (click to toggle)
linuxcnc 2.9.0~pre1%2Bgit20230208.f1270d6ed7-1%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 274,984 kB
  • sloc: python: 142,166; ansic: 103,241; cpp: 99,140; tcl: 16,045; xml: 10,608; sh: 10,124; makefile: 1,229; javascript: 226; sql: 72; asm: 15
file content (285 lines) | stat: -rw-r--r-- 10,620 bytes parent folder | download
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
"""
LinuxCNC User Interface helper functions
"""

import linuxcnc

import sys
import time
import math


class LinuxCNC_Exception(Exception):
    pass


class LinuxCNC:
    """
    This class implements the main interface to LinuxCNC.
    """

    def __init__(self, command=None, status=None, error=None):
        """init docs"""
        self.command = command
        self.status = status
        self.error = error

        if not self.command:
            self.command = linuxcnc.command()

        if not self.status:
            self.status = linuxcnc.stat()

        if not self.error:
            self.error = linuxcnc.error_channel()


    def wait_for_linuxcnc_startup(self, timeout=10.0):

        """Poll the Status buffer waiting for it to look initialized,
        rather than just allocated (all-zero).  Returns on success, throws
        RuntimeError on failure."""

        start_time = time.time()
        while time.time() - start_time < timeout:
            self.status.poll()
            if (self.status.angular_units == 0.0) \
                or (self.status.axis_mask == 0) \
                or (self.status.cycle_time == 0.0) \
                or (self.status.exec_state != linuxcnc.EXEC_DONE) \
                or (self.status.interp_state != linuxcnc.INTERP_IDLE) \
                or (self.status.inpos == False) \
                or (self.status.linear_units == 0.0) \
                or (self.status.max_acceleration == 0.0) \
                or (self.status.max_velocity == 0.0) \
                or (self.status.program_units == 0.0) \
                or (self.status.rapidrate == 0.0) \
                or (self.status.state != linuxcnc.STATE_ESTOP) \
                or (self.status.task_state != linuxcnc.STATE_ESTOP):
                time.sleep(0.1)
            else:
                # looks good
                return

        # timeout, throw an exception
        raise RuntimeError


    def all_joints_homed(self, joints):
        """Arguments:

            'joints' is an array of booleans, indicating the joints to
            check for homed-ness.

        Returns True if all the specified joints are homed, False if
        any are unhomed."""

        self.status.poll()
        for i in range(0,9):
            if joints[i] and not self.status.homed[i]:
                return False
        return True


    def wait_for_home(self, joints, timeout=10.0):
        """Arguments:

            'joints' is an array of booleans, indicating the joints that
            are homing.

            'timeout' is a float, the number of seconds to wait for
            homing before giving up.

        Returns if all the specified joints homed before the timeout,
        raises LinuxCNC_Exception if the timeout expired first."""

        start_time = time.time()
        while (time.time() - start_time) < timeout:
            if self.all_joints_homed(joints):
                return
            time.sleep(0.1)

        raise LinuxCNC_Exception("timeout waiting for homing to complete:\nstatus.homed:" + str(self.status.homed) + "\nstatus.position:" + str(self.status.position))


    def wait_for_axis_to_stop(self, axis_letter, timeout=10.0):
        """Arguments:
            'axis_letter' is a single character from the set [xyzabcuvw]
            indicating the axis to wait for stillness on.

            'timeout' is a float, the number of seconds to wait for the
            axis to stop before giving up.

        Returns if the specified axis stops moving before the timeout
        expires.  Raises LinuxCNC_Exception if the timeout expires before
        the axis stops.
        """

        axis_letter = axis_letter.lower()
        axis_index = 'xyzabcuvw'.index(axis_letter)
        print("waiting for axis", axis_letter, "to stop")
        self.status.poll()
        start_time = time.time()
        prev_pos = self.status.position[axis_index]
        while (time.time() - start_time) < timeout:
            time.sleep(0.1)
            self.status.poll()
            new_pos = self.status.position[axis_index]
            if new_pos == prev_pos:
                return
            prev_pos = new_pos
        raise LinuxCNC_Exception("axis %s didn't stop jogging!\n" % axis_letter + "axis %s is at %.3f %.3f seconds after reaching target (prev_pos=%.3f)\n" % (axis_letter, self.status.position[axis_index], timeout, prev_pos))


    def jog_axis(self, axis_letter, target, vel=5.0, timeout=10.0):
        """Arguments:

            'axis_letter' is a single character from the set [xyzabcuvw]
            indicating an axis.

            'target' is a float indicating the location to jog to.

            'vel' is a float indicating the jog speed.

            'timeout' is a float, the number of seconds to wait for the
            jog to reach the target before giving up.

        This function uses the linuxcnc.command.jog() function to do
        a continuous jog of the specified axis towards the target, at
        the specified speed.  Stops the jog when the target is reached.
        Will overshoot some.  The function returns after the axis has
        stopped moving.

        If the axis does not reach the target before the timeout, or if
        any other axis moved, raises LinuxCNC_Exeption.
        """

        self.status.poll()
        axis_letter = axis_letter.lower()
        axis_index = 'xyzabcuvw'.index(axis_letter)
        start_pos = self.status.position

        print("jogging axis %s from %.3f to %.3f" % (axis_letter, start_pos[axis_index], target))

        if self.status.position[axis_index] < target:
            vel = abs(vel)
            done = lambda pos: pos > target
        else:
            vel = -1.0 * abs(vel)
            done = lambda pos: pos < target

        # the 0 here means "jog axis, not joint"
        self.command.jog(linuxcnc.JOG_CONTINUOUS, 0, axis_index, vel)

        start = time.time()
        while not done(self.status.position[axis_index]) and ((time.time() - start) < timeout):
            time.sleep(0.1)
            self.status.poll()

        # the 0 here means "jog axis, not joint"
        self.command.jog(linuxcnc.JOG_STOP, 0, axis_index)

        if not done(self.status.position[axis_index]):
            raise LinuxCNC_Exception("failed to jog axis %s to %.3f\n" % (axis_letter, target) + "timed out at %.3f after %.3f seconds" % (self.status.position[axis_index], timeout))

        print("    jogged axis %d past target %.3f" % (axis_index, target))

        self.wait_for_axis_to_stop(axis_letter)

        success = True
        for i in range(0, 9):
            if i == axis_index:
                continue;
            if start_pos[i] != self.status.position[i]:
                raise LinuxCNC_Exception("axis %s moved from %.3f to %.3f but should not have!" % ('xyzabcuvw'[i], start_pos[i], self.status.position[i]))


    def wait_for_axis_to_stop_at(self, axis_letter, target, timeout=10.0, tolerance = 0.0001):
        """
        Arguments:
            'axis_letter' is a single character from the set [xyzabcuvw]
            indicating the axis to wait for stillness on.

            'target' is a float, where the specified axis is trying to
            move to.

            'timeout' is a float, the number of seconds to wait for the
            axis to stop before giving up.

            'tolerance' is a float, how close to the target the axis
            has to be before we consider it there.

        This function polls the LinuxCNC Status buffer and monitors the
        position field, waiting for the specified axis to come to rest
        at the specified target.  If this does not happen before the
        timeout, the function raises LinuxCNC_Exception.
        """

        axis_letter = axis_letter.lower()
        axis_index = 'xyzabcuvw'.index(axis_letter)

        self.status.poll()
        start = time.time()

        while ((time.time() - start) < timeout):
            prev_pos = self.status.position[axis_index]
            self.status.poll()
            vel = self.status.position[axis_index] - prev_pos
            error = math.fabs(self.status.position[axis_index] - target)
            if (error < tolerance) and (vel == 0):
                print("axis %s stopped at %.3f" % (axis_letter, target))
                return
            time.sleep(0.1)
        raise LinuxCNC_Exception("timeout waiting for axis %s to stop at %.3f (pos=%.3f, vel=%.3f)" % (axis_letter, target, self.status.position[axis_index], vel))


    def wait_for_interp_state(self, target_state, timeout=10.0):
        """
        Arguments:
            'target_state' is the Interpreter state to wait for,
            one of linuxcnc.INTERP_IDLE, linuxcnc.INTERP_PAUSED,
            linuxcnc.INTERP_READING, or linuxcnc.INTERP_WAITING.

            'timeout' is a float, the number of seconds to wait for the
            Interpreter to reach the target state.

        This function polls the LinuxCNC Status buffer waiting for the
        specified Interpreter state.  If the timeout expires before
        the Interpreter reaches the specified status, it raises
        LinuxCNC_Exception.
        """

        start_time = time.time()
        while (time.time() - start_time) < timeout:
            self.status.poll()
            if self.status.interp_state == target_state:
                return
            time.sleep(0.001)

        if self.status.interp_state != target_state:
            raise LinuxCNC_Exception("interpreter state %d did not reach target state %d" % (self.state.interp_state, target_state))


    def wait_for_tool_in_spindle(self, expected_tool, timeout=10.0):
        """
        Arguments:
            'expected_tool', integer, the tool we're waiting to find in
            the spindle.

            'timeout', float, the number of seconds to wait for the
            specified tool to show up in the spindle.

        This function polls the LinuxCNC Status buffer, waiting for the
        specified tool to appear in the spindle.  If the timeout expires
        before the tool appears, it raises LinuxCNC_Exception.
        """

        start_time = time.time()
        while (time.time() - start_time) < timeout:
            time.sleep(0.1)
            self.status.poll()
            if self.status.tool_in_spindle == expected_tool:
                print("the Stat buffer's toolInSpindle reached the value of %d after %f seconds" % (expected_tool, time.time() - start_time))
                return
        raise LinuxCNC_Exception("the Stat buffer's toolInSpindle value is %d, expected %d" % (self.status.tool_in_spindle, expected_tool))