From bae973e1c9f0a704d57947114f3718cab52f3807 Mon Sep 17 00:00:00 2001 From: Sebastian Kuzminsky Date: Tue, 20 Feb 2018 22:17:05 -0700 Subject: [PATCH 1/3] test: add tests of reloading the loaded tool These tests verify the behavior when the user tries to prepare ("T") and change to ("M6") the tool that's currently loaded in the spindle. These tests reproduce #330 and #409. --- tests/toolchanger/reload-tool/README | 3 + tests/toolchanger/reload-tool/checkresult | 2 + tests/toolchanger/reload-tool/core_sim.hal | 60 ++++ .../reload-tool/non-random/checkresult | 1 + .../reload-tool/non-random/core_sim.hal | 1 + .../reload-tool/non-random/postgui.hal | 1 + .../reload-tool/non-random/test-ui.py | 273 ++++++++++++++++++ .../reload-tool/non-random/test.ini | 82 ++++++ .../reload-tool/non-random/test.sh | 1 + tests/toolchanger/reload-tool/postgui.hal | 22 ++ .../reload-tool/random/checkresult | 1 + .../reload-tool/random/core_sim.hal | 1 + .../reload-tool/random/postgui.hal | 1 + .../toolchanger/reload-tool/random/test-ui.py | 264 +++++++++++++++++ tests/toolchanger/reload-tool/random/test.ini | 82 ++++++ tests/toolchanger/reload-tool/random/test.sh | 1 + tests/toolchanger/reload-tool/shared-test.sh | 5 + .../reload-tool/simpockets.tbl.save | 16 + 18 files changed, 817 insertions(+) create mode 100644 tests/toolchanger/reload-tool/README create mode 100755 tests/toolchanger/reload-tool/checkresult create mode 100644 tests/toolchanger/reload-tool/core_sim.hal create mode 120000 tests/toolchanger/reload-tool/non-random/checkresult create mode 120000 tests/toolchanger/reload-tool/non-random/core_sim.hal create mode 120000 tests/toolchanger/reload-tool/non-random/postgui.hal create mode 100755 tests/toolchanger/reload-tool/non-random/test-ui.py create mode 100644 tests/toolchanger/reload-tool/non-random/test.ini create mode 120000 tests/toolchanger/reload-tool/non-random/test.sh create mode 100644 tests/toolchanger/reload-tool/postgui.hal create mode 120000 tests/toolchanger/reload-tool/random/checkresult create mode 120000 tests/toolchanger/reload-tool/random/core_sim.hal create mode 120000 tests/toolchanger/reload-tool/random/postgui.hal create mode 100755 tests/toolchanger/reload-tool/random/test-ui.py create mode 100644 tests/toolchanger/reload-tool/random/test.ini create mode 120000 tests/toolchanger/reload-tool/random/test.sh create mode 100755 tests/toolchanger/reload-tool/shared-test.sh create mode 100644 tests/toolchanger/reload-tool/simpockets.tbl.save diff --git a/tests/toolchanger/reload-tool/README b/tests/toolchanger/reload-tool/README new file mode 100644 index 00000000000..df4e77cdd43 --- /dev/null +++ b/tests/toolchanger/reload-tool/README @@ -0,0 +1,3 @@ +This test reproduces https://github.com/LinuxCNC/linuxcnc/issues/330. + +It tests the behavior for both random and non-random toolchanger machines. diff --git a/tests/toolchanger/reload-tool/checkresult b/tests/toolchanger/reload-tool/checkresult new file mode 100755 index 00000000000..24dc9aa53e3 --- /dev/null +++ b/tests/toolchanger/reload-tool/checkresult @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 # test failure is indicated by test.sh exit value diff --git a/tests/toolchanger/reload-tool/core_sim.hal b/tests/toolchanger/reload-tool/core_sim.hal new file mode 100644 index 00000000000..0448af4cece --- /dev/null +++ b/tests/toolchanger/reload-tool/core_sim.hal @@ -0,0 +1,60 @@ +# core HAL config file for simulation + +# first load all the RT modules that will be needed +# kinematics +loadrt trivkins +# motion controller, get name and thread periods from ini file +loadrt [EMCMOT]EMCMOT base_period_nsec=[EMCMOT]BASE_PERIOD servo_period_nsec=[EMCMOT]SERVO_PERIOD num_joints=[TRAJ]AXES +# load 6 differentiators (for velocity and accel signals +loadrt ddt count=6 +# load additional blocks +loadrt hypot count=2 +loadrt comp count=3 +loadrt or2 count=1 + +# add motion controller functions to servo thread +addf motion-command-handler servo-thread +addf motion-controller servo-thread +# link the differentiator functions into the code +addf ddt.0 servo-thread +addf ddt.1 servo-thread +addf ddt.2 servo-thread +addf ddt.3 servo-thread +addf ddt.4 servo-thread +addf ddt.5 servo-thread +addf hypot.0 servo-thread +addf hypot.1 servo-thread + +# create HAL signals for position commands from motion module +# loop position commands back to motion module feedback +net Xpos axis.0.motor-pos-cmd => axis.0.motor-pos-fb ddt.0.in +net Ypos axis.1.motor-pos-cmd => axis.1.motor-pos-fb ddt.2.in +net Zpos axis.2.motor-pos-cmd => axis.2.motor-pos-fb ddt.4.in + +# send the position commands thru differentiators to +# generate velocity and accel signals +net Xvel ddt.0.out => ddt.1.in hypot.0.in0 +net Xacc <= ddt.1.out +net Yvel ddt.2.out => ddt.3.in hypot.0.in1 +net Yacc <= ddt.3.out +net Zvel ddt.4.out => ddt.5.in hypot.1.in0 +net Zacc <= ddt.5.out + +# Cartesian 2- and 3-axis velocities +net XYvel hypot.0.out => hypot.1.in1 +net XYZvel <= hypot.1.out + +# estop loopback +net estop-loop iocontrol.0.user-enable-out iocontrol.0.emc-enable-in + +# create signals for tool loading loopback +net tool-prepare <= iocontrol.0.tool-prepare +net tool-prepared => iocontrol.0.tool-prepared + +net tool-change <= iocontrol.0.tool-change +net tool-changed => iocontrol.0.tool-changed + +net tool-number <= iocontrol.0.tool-number +net tool-prep-number <= iocontrol.0.tool-prep-number +net tool-prep-pocket <= iocontrol.0.tool-prep-pocket + diff --git a/tests/toolchanger/reload-tool/non-random/checkresult b/tests/toolchanger/reload-tool/non-random/checkresult new file mode 120000 index 00000000000..e826ab2e5b2 --- /dev/null +++ b/tests/toolchanger/reload-tool/non-random/checkresult @@ -0,0 +1 @@ +../checkresult \ No newline at end of file diff --git a/tests/toolchanger/reload-tool/non-random/core_sim.hal b/tests/toolchanger/reload-tool/non-random/core_sim.hal new file mode 120000 index 00000000000..ead32827019 --- /dev/null +++ b/tests/toolchanger/reload-tool/non-random/core_sim.hal @@ -0,0 +1 @@ +../core_sim.hal \ No newline at end of file diff --git a/tests/toolchanger/reload-tool/non-random/postgui.hal b/tests/toolchanger/reload-tool/non-random/postgui.hal new file mode 120000 index 00000000000..d5ae19df5df --- /dev/null +++ b/tests/toolchanger/reload-tool/non-random/postgui.hal @@ -0,0 +1 @@ +../postgui.hal \ No newline at end of file diff --git a/tests/toolchanger/reload-tool/non-random/test-ui.py b/tests/toolchanger/reload-tool/non-random/test-ui.py new file mode 100755 index 00000000000..aa3f224784a --- /dev/null +++ b/tests/toolchanger/reload-tool/non-random/test-ui.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python + +import linuxcnc +import hal + +import math +import time +import sys +import subprocess +import os +import signal +import glob +import re + + +def wait_for_linuxcnc_startup(status, 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: + status.poll() + if (status.angular_units == 0.0) \ + or (status.axes == 0) \ + or (status.axis_mask == 0) \ + or (status.cycle_time == 0.0) \ + or (status.exec_state != linuxcnc.EXEC_DONE) \ + or (status.interp_state != linuxcnc.INTERP_IDLE) \ + or (status.inpos == False) \ + or (status.linear_units == 0.0) \ + or (status.max_acceleration == 0.0) \ + or (status.max_velocity == 0.0) \ + or (status.program_units == 0.0) \ + or (status.rapidrate == 0.0) \ + or (status.state != linuxcnc.STATE_ESTOP) \ + or (status.task_state != linuxcnc.STATE_ESTOP): + time.sleep(0.1) + else: + # looks good + return + + # timeout, throw an exception + raise RuntimeError + + +def wait_for_hal_pin(name, value, timeout=10): + start_time = time.time() + while (time.time() - start_time) < timeout: + if h[name] == value: + return + time.sleep(0.1) + raise RuntimeError("hal pin %s didn't get to %s after %.3f seconds" % (name, value, timeout)) + + +# After doing something that should change the stat buffer, wait this +# long before polling to let the change propagate through. +# FIXME: this is bogus +stat_poll_wait = 0.100 + + +c = linuxcnc.command() +s = linuxcnc.stat() +e = linuxcnc.error_channel() + +h = hal.component("test-ui") + +h.newpin("tool-change", hal.HAL_BIT, hal.HAL_IN) +h.newpin("tool-changed", hal.HAL_BIT, hal.HAL_OUT) +h["tool-changed"] = False + +h.newpin("tool-prepare", hal.HAL_BIT, hal.HAL_IN) +h.newpin("tool-prepared", hal.HAL_BIT, hal.HAL_OUT) +h["tool-prepared"] = False + +h.newpin("tool-number", hal.HAL_S32, hal.HAL_IN) +h.newpin("tool-prep-number", hal.HAL_S32, hal.HAL_IN) +h.newpin("tool-prep-pocket", hal.HAL_S32, hal.HAL_IN) + +h.ready() + +os.system("halcmd source ./postgui.hal") + + +# Wait for LinuxCNC to initialize itself so the Status buffer stabilizes. +wait_for_linuxcnc_startup(s) + +c.state(linuxcnc.STATE_ESTOP_RESET) +c.state(linuxcnc.STATE_ON) +c.home(-1) +c.wait_complete() + +c.mode(linuxcnc.MODE_MDI) + + +# +# At startup there's no tool in the spindle and no tool prep or change +# is being requested. +# + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 0) +assert(h['tool-prep-number'] == 0) +assert(h['tool-prep-pocket'] == 0) + +s.poll() +assert(s.tool_in_spindle == 0) +assert(s.pocket_prepped == -1) + + +# +# Prepare T2 +# + +c.mdi('t2') +wait_for_hal_pin('tool-prepare', True) + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == True) +assert(h['tool-number'] == 0) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +s.poll() +assert(s.tool_in_spindle == 0) +assert(s.pocket_prepped == -1) + +h['tool-prepared'] = True +wait_for_hal_pin('tool-prepare', False) +h['tool-prepared'] = False + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 0) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 0) +assert(s.pocket_prepped == 6) # ugh, non-random tc gives you tool-table-array index, not pocket + + +# +# Change to T2 +# + +c.mdi('m6') +wait_for_hal_pin('tool-change', True) + +assert(h['tool-change'] == True) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 0) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 0) +assert(s.pocket_prepped == 6) + +h['tool-changed'] = True +wait_for_hal_pin('tool-change', False) +h['tool-changed'] = False + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 0) +assert(h['tool-prep-pocket'] == 0) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == -1) + + +# +# Prepare T12 +# + +c.mdi('t12') +wait_for_hal_pin('tool-prepare', True) + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == True) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 12) +assert(h['tool-prep-pocket'] == 9) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == -1) + +h['tool-prepared'] = True +wait_for_hal_pin('tool-prepare', False) +h['tool-prepared'] = False + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 12) +assert(h['tool-prep-pocket'] == 9) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == 4) + + +# +# Prepare T2 +# This tool is already in the spindle. +# + +c.mdi('t2') +wait_for_hal_pin('tool-prepare', True) + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == True) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == 4) + +h['tool-prepared'] = True +wait_for_hal_pin('tool-prepare', False) +h['tool-prepared'] = False + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == 6) + + +# +# Change to prepared tool (T2 again) +# + +c.mdi('m6') +try: + wait_for_hal_pin('tool-change', True, timeout=5) +except RuntimeError: + # It *should* time out, no tool change should be performed since + # the prepared tool is already in the spindle. + pass + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == 6) + + +sys.exit(0) diff --git a/tests/toolchanger/reload-tool/non-random/test.ini b/tests/toolchanger/reload-tool/non-random/test.ini new file mode 100644 index 00000000000..66e8cab0521 --- /dev/null +++ b/tests/toolchanger/reload-tool/non-random/test.ini @@ -0,0 +1,82 @@ +[EMC] +#DEBUG = 0x0 +DEBUG = 0xffffffff + +[DISPLAY] +DISPLAY = ./test-ui.py + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var +USER_M_PATH = ./subs + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +COMM_WAIT = 0.010 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[HAL] +HALFILE = core_sim.hal + +[TRAJ] +NO_FORCE_HOMING=1 +AXES = 3 +COORDINATES = X Y Z +HOME = 0 0 0 +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +CYCLE_TIME = 0.010 +DEFAULT_VELOCITY = 1.2 +MAX_ACCELERATION = 123.45 +MAX_VELOCITY = 45.67 + +[AXIS_0] +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[AXIS_1] +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[AXIS_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[EMCIO] +EMCIO = io +CYCLE_TIME = 0.100 +TOOL_TABLE = simpockets.tbl +TOOL_CHANGE_QUILL_UP = 1 +RANDOM_TOOLCHANGER = 0 diff --git a/tests/toolchanger/reload-tool/non-random/test.sh b/tests/toolchanger/reload-tool/non-random/test.sh new file mode 120000 index 00000000000..0b01664e62e --- /dev/null +++ b/tests/toolchanger/reload-tool/non-random/test.sh @@ -0,0 +1 @@ +../shared-test.sh \ No newline at end of file diff --git a/tests/toolchanger/reload-tool/postgui.hal b/tests/toolchanger/reload-tool/postgui.hal new file mode 100644 index 00000000000..0b14c365b89 --- /dev/null +++ b/tests/toolchanger/reload-tool/postgui.hal @@ -0,0 +1,22 @@ + +net tool-change <= iocontrol.0.tool-change +net tool-change => test-ui.tool-change + +net tool-changed <= test-ui.tool-changed +net tool-changed => iocontrol.0.tool-changed + +net tool-prepare <= iocontrol.0.tool-prepare +net tool-prepare => test-ui.tool-prepare + +net tool-prepared <= test-ui.tool-prepared +net tool-prepared => iocontrol.0.tool-prepared + +net tool-number <= iocontrol.0.tool-number +net tool-number => test-ui.tool-number + +net tool-prep-number <= iocontrol.0.tool-prep-number +net tool-prep-number => test-ui.tool-prep-number + +net tool-prep-pocket <= iocontrol.0.tool-prep-pocket +net tool-prep-pocket => test-ui.tool-prep-pocket + diff --git a/tests/toolchanger/reload-tool/random/checkresult b/tests/toolchanger/reload-tool/random/checkresult new file mode 120000 index 00000000000..e826ab2e5b2 --- /dev/null +++ b/tests/toolchanger/reload-tool/random/checkresult @@ -0,0 +1 @@ +../checkresult \ No newline at end of file diff --git a/tests/toolchanger/reload-tool/random/core_sim.hal b/tests/toolchanger/reload-tool/random/core_sim.hal new file mode 120000 index 00000000000..ead32827019 --- /dev/null +++ b/tests/toolchanger/reload-tool/random/core_sim.hal @@ -0,0 +1 @@ +../core_sim.hal \ No newline at end of file diff --git a/tests/toolchanger/reload-tool/random/postgui.hal b/tests/toolchanger/reload-tool/random/postgui.hal new file mode 120000 index 00000000000..d5ae19df5df --- /dev/null +++ b/tests/toolchanger/reload-tool/random/postgui.hal @@ -0,0 +1 @@ +../postgui.hal \ No newline at end of file diff --git a/tests/toolchanger/reload-tool/random/test-ui.py b/tests/toolchanger/reload-tool/random/test-ui.py new file mode 100755 index 00000000000..cf6b76538ae --- /dev/null +++ b/tests/toolchanger/reload-tool/random/test-ui.py @@ -0,0 +1,264 @@ +#!/usr/bin/env python + +import linuxcnc +import hal + +import math +import time +import sys +import subprocess +import os +import signal +import glob +import re + + +def wait_for_linuxcnc_startup(status, 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: + status.poll() + if (status.angular_units == 0.0) \ + or (status.axes == 0) \ + or (status.axis_mask == 0) \ + or (status.cycle_time == 0.0) \ + or (status.exec_state != linuxcnc.EXEC_DONE) \ + or (status.interp_state != linuxcnc.INTERP_IDLE) \ + or (status.inpos == False) \ + or (status.linear_units == 0.0) \ + or (status.max_acceleration == 0.0) \ + or (status.max_velocity == 0.0) \ + or (status.program_units == 0.0) \ + or (status.rapidrate == 0.0) \ + or (status.state != linuxcnc.STATE_ESTOP) \ + or (status.task_state != linuxcnc.STATE_ESTOP): + time.sleep(0.1) + else: + # looks good + return + + # timeout, throw an exception + raise RuntimeError + + +def wait_for_hal_pin(name, value, timeout=10): + start_time = time.time() + while (time.time() - start_time) < timeout: + if h[name] == value: + return + time.sleep(0.1) + raise RuntimeError("hal pin %s didn't get to %s after %.3f seconds" % (name, value, timeout)) + + +# After doing something that should change the stat buffer, wait this +# long before polling to let the change propagate through. +# FIXME: this is bogus +stat_poll_wait = 0.100 + + +c = linuxcnc.command() +s = linuxcnc.stat() +e = linuxcnc.error_channel() + +h = hal.component("test-ui") + +h.newpin("tool-change", hal.HAL_BIT, hal.HAL_IN) +h.newpin("tool-changed", hal.HAL_BIT, hal.HAL_OUT) +h["tool-changed"] = False + +h.newpin("tool-prepare", hal.HAL_BIT, hal.HAL_IN) +h.newpin("tool-prepared", hal.HAL_BIT, hal.HAL_OUT) +h["tool-prepared"] = False + +h.newpin("tool-number", hal.HAL_S32, hal.HAL_IN) +h.newpin("tool-prep-number", hal.HAL_S32, hal.HAL_IN) +h.newpin("tool-prep-pocket", hal.HAL_S32, hal.HAL_IN) + +h.ready() + +os.system("halcmd source ./postgui.hal") + + +# Wait for LinuxCNC to initialize itself so the Status buffer stabilizes. +wait_for_linuxcnc_startup(s) + +c.state(linuxcnc.STATE_ESTOP_RESET) +c.state(linuxcnc.STATE_ON) +c.home(-1) +c.wait_complete() + +c.mode(linuxcnc.MODE_MDI) + + +# +# At startup tool 3 is in the spindle and no tool prep or change is +# being requested. +# + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 3) +assert(h['tool-prep-number'] == 0) +assert(h['tool-prep-pocket'] == 0) + +s.poll() +assert(s.tool_in_spindle == 3) +assert(s.pocket_prepped == -1) + + +# +# Prepare T2 +# + +c.mdi('t2') +wait_for_hal_pin('tool-prepare', True) + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == True) +assert(h['tool-number'] == 3) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +s.poll() +assert(s.tool_in_spindle == 3) +assert(s.pocket_prepped == -1) + +h['tool-prepared'] = True +wait_for_hal_pin('tool-prepare', False) +h['tool-prepared'] = False + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 3) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 3) +assert(s.pocket_prepped == 46) # random tc gives you pocket, which is the same as tool-table-array index + + +# +# Change to T2 +# + +c.mdi('m6') +wait_for_hal_pin('tool-change', True) + +assert(h['tool-change'] == True) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 3) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 46) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 3) +assert(s.pocket_prepped == 46) + +h['tool-changed'] = True +wait_for_hal_pin('tool-change', False) +h['tool-changed'] = False + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 0) +assert(h['tool-prep-pocket'] == 0) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == -1) + + +# +# Prepare T12 +# + +c.mdi('t12') +wait_for_hal_pin('tool-prepare', True) + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == True) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 12) +assert(h['tool-prep-pocket'] == 9) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == -1) + +h['tool-prepared'] = True +wait_for_hal_pin('tool-prepare', False) +h['tool-prepared'] = False + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 12) +assert(h['tool-prep-pocket'] == 9) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == 9) + + +# +# Prepare T2 +# This tool is already in the spindle. +# + +c.mdi('t2') +try: + wait_for_hal_pin('tool-prepare', True, timeout=5) +except RuntimeError: + # It *should* time out, no tool prep should be performed since the + # requested tool is already in the spindle. + pass + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 0) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == 0) + + +# +# Change to prepared tool (T2) +# + +c.mdi('m6') +try: + wait_for_hal_pin('tool-change', True, timeout=5) +except RuntimeError: + # It *should* time out, no tool change should be performed since + # the prepared tool is already in the spindle. + pass + +assert(h['tool-change'] == False) +assert(h['tool-prepare'] == False) +assert(h['tool-number'] == 2) +assert(h['tool-prep-number'] == 2) +assert(h['tool-prep-pocket'] == 0) + +time.sleep(stat_poll_wait) +s.poll() +assert(s.tool_in_spindle == 2) +assert(s.pocket_prepped == 0) + + +sys.exit(0) + diff --git a/tests/toolchanger/reload-tool/random/test.ini b/tests/toolchanger/reload-tool/random/test.ini new file mode 100644 index 00000000000..27ff19b2c68 --- /dev/null +++ b/tests/toolchanger/reload-tool/random/test.ini @@ -0,0 +1,82 @@ +[EMC] +#DEBUG = 0x0 +DEBUG = 0xffffffff + +[DISPLAY] +DISPLAY = ./test-ui.py + +[TASK] +TASK = milltask +CYCLE_TIME = 0.001 + +[RS274NGC] +PARAMETER_FILE = sim.var +USER_M_PATH = ./subs + +[EMCMOT] +EMCMOT = motmod +COMM_TIMEOUT = 4.0 +COMM_WAIT = 0.010 +BASE_PERIOD = 0 +SERVO_PERIOD = 1000000 + +[HAL] +HALFILE = core_sim.hal + +[TRAJ] +NO_FORCE_HOMING=1 +AXES = 3 +COORDINATES = X Y Z +HOME = 0 0 0 +LINEAR_UNITS = inch +ANGULAR_UNITS = degree +CYCLE_TIME = 0.010 +DEFAULT_VELOCITY = 1.2 +MAX_ACCELERATION = 123.45 +MAX_VELOCITY = 45.67 + +[AXIS_0] +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[AXIS_1] +TYPE = LINEAR +HOME = 0.000 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[AXIS_2] +TYPE = LINEAR +HOME = 0.0 +MAX_VELOCITY = 4 +MAX_ACCELERATION = 1000.0 +BACKLASH = 0.000 +INPUT_SCALE = 4000 +OUTPUT_SCALE = 1.000 +MIN_LIMIT = -40.0 +MAX_LIMIT = 40.0 +FERROR = 0.050 +MIN_FERROR = 0.010 + +[EMCIO] +EMCIO = io +CYCLE_TIME = 0.100 +TOOL_TABLE = simpockets.tbl +TOOL_CHANGE_QUILL_UP = 1 +RANDOM_TOOLCHANGER = 1 diff --git a/tests/toolchanger/reload-tool/random/test.sh b/tests/toolchanger/reload-tool/random/test.sh new file mode 120000 index 00000000000..0b01664e62e --- /dev/null +++ b/tests/toolchanger/reload-tool/random/test.sh @@ -0,0 +1 @@ +../shared-test.sh \ No newline at end of file diff --git a/tests/toolchanger/reload-tool/shared-test.sh b/tests/toolchanger/reload-tool/shared-test.sh new file mode 100755 index 00000000000..d6a1418f77e --- /dev/null +++ b/tests/toolchanger/reload-tool/shared-test.sh @@ -0,0 +1,5 @@ +#!/bin/bash +rm -f sim.var +rm -f simpockets.tbl +cp ../simpockets.tbl.save simpockets.tbl +linuxcnc -r test.ini diff --git a/tests/toolchanger/reload-tool/simpockets.tbl.save b/tests/toolchanger/reload-tool/simpockets.tbl.save new file mode 100644 index 00000000000..b568b078932 --- /dev/null +++ b/tests/toolchanger/reload-tool/simpockets.tbl.save @@ -0,0 +1,16 @@ +T3 P0 D2.250000 Z-6.595331 ;2-1/4 face mill +T10 P6 Z-3.406343 ;other big jacobs chuck +T16 P3 ;little jacobs chuck +T12 P9 Z-4.596806 ;1/2 2fl long em +T6 P51 Z-0.950266 ;big jacobs chuck +T2 P46 D0.750000 Z-6.366394 ;3/4 2 flute +T1 P37 D0.750000 Z-5.319396 ;3/4 roughing +T7 P28 Z-2.979905 ;big albrecht drill chuck .25 drill +T11 P19 D0.125000 Z-6.307857 ;1/8 2fl end mill +T15 P5 Z-3.730620 ;little albrecht chuck spot drill +T0 P2 ;no tool +T14 P11 Z-5.305736 ; +T8 P54 Z-7.213145 ;V engraving tool +T9 P44 Z-6.163994 ;90 deg 3/8 mill-drill +T5 P35 Z-2.825524 ;long ER40 collet chuck +T4 P26 D0.375000 Z-5.307185 ;3/8 4fl carbide From d617b6dd67fd5b830106855672f68e586f555d3b Mon Sep 17 00:00:00 2001 From: Sebastian Kuzminsky Date: Wed, 21 Feb 2018 17:06:57 -0700 Subject: [PATCH 2/3] io: set the HAL pins/params even for the loaded tool This fixes #330. Before this commit, this sequence of G-code commands led to incorrect behavior: N1 T1 N2 M6 N3 T2 N4 T1 N5 M6 The T2 on N3 would set io's .tool-prep-number and .tool-prep-pocket pins, but the T1 on N4 would not, so the pins would keep their old T2 values. The M6 on N5 would incorrectly load T2 instead of T1. The same problem would arise in a program without N4, if the program was aborted after N3 and before N5. This commit fixes the problem by setting io's hal pins even for the tool in P0. --- src/emc/iotask/ioControl.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/emc/iotask/ioControl.cc b/src/emc/iotask/ioControl.cc index 788a2d1cd4a..45903864cdc 100644 --- a/src/emc/iotask/ioControl.cc +++ b/src/emc/iotask/ioControl.cc @@ -864,9 +864,6 @@ int main(int argc, char *argv[]) int t = ((EMC_TOOL_PREPARE*)emcioCommand)->tool; rtapi_print_msg(RTAPI_MSG_DBG, "EMC_TOOL_PREPARE tool=%d pocket=%d\n", t, p); - // it doesn't make sense to prep the spindle pocket - if(random_toolchanger && p == 0) break; - // Set HAL pins/params for tool number, pocket, and index. iocontrol_data->tool_prep_index = p; *(iocontrol_data->tool_prep_pocket) = random_toolchanger? p: fms[p]; @@ -875,6 +872,12 @@ int main(int argc, char *argv[]) } else { *(iocontrol_data->tool_prep_number) = emcioStatus.tool.toolTable[p].toolno; } + + // it doesn't make sense to prep the spindle pocket + if (random_toolchanger && p == 0) { + break; + } + /* then set the prepare pin to tell external logic to get started */ *(iocontrol_data->tool_prepare) = 1; // the feedback logic is done inside read_hal_inputs() From 40b354536593f487648d0eb1f56a80af62e81162 Mon Sep 17 00:00:00 2001 From: Sebastian Kuzminsky Date: Wed, 21 Feb 2018 17:12:09 -0700 Subject: [PATCH 3/3] io: update the status buffer when prepping the loaded tool Before this commit, prepping the loaded tool would fail to update the prepped pocket field of the Status buffer, thus presenting incorrect information to Task and the GUIs. --- src/emc/iotask/ioControl.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/emc/iotask/ioControl.cc b/src/emc/iotask/ioControl.cc index 45903864cdc..32fa19e72d9 100644 --- a/src/emc/iotask/ioControl.cc +++ b/src/emc/iotask/ioControl.cc @@ -875,6 +875,7 @@ int main(int argc, char *argv[]) // it doesn't make sense to prep the spindle pocket if (random_toolchanger && p == 0) { + emcioStatus.tool.pocketPrepped = 0; break; }