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