Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/src/config/python-interface.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,10 @@ see <<python:reading-ini-values,ReadingINI file values>> for an example.
flag, True if a probe operation is in progress.

*program_units*:: '(returns integer)' -
one of CANON_UNITS_INCHES=1, CANON_UNITS_MM=2, CANON_UNITS_CM=3
one of CANON_UNITS_INCHES=1, CANON_UNITS_MM=2, CANON_UNITS_CM=3.
Follows the active G20/G21 reported in *gcodes*: the executing line while
a program runs, the interpreter otherwise. CANON_UNITS_CM is never reported:
G-code cannot select it and canterp maps it to mm.

*queue*:: '(returns integer)' -
current size of the trajectory planner queue.
Expand Down
12 changes: 12 additions & 0 deletions src/emc/task/emctask.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "nml_intf/interpl_nml.hh" // NML_INTERP_LIST, interp_list
#include "nml_intf/canon.hh" // CANON_VECTOR, GET_PROGRAM_ORIGIN()
#include "rs274ngc/rs274ngc_interp.hh" // the interpreter
#include "rs274ngc/interp_internal.hh" // G_20, G_21
#include "nml_intf/interp_return.hh" // INTERP_FILE_NOT_OPEN
#include <inifile.hh>

Expand Down Expand Up @@ -763,6 +764,17 @@ int emcTaskUpdate(EMC_TASK_STAT * stat)
interp.active_settings(&stat->activeSettings[0]);
}

// program_units follows the active G20/G21 above, so it describes the
// same point in the program as gcodes does: the executing move while a
// program runs, the interpreter otherwise. Canon also sets it as the
// interpreter reads ahead, which alone reported a G20 read ahead of a
// still-running G21 move (issue #3627). Canon's value stays when the
// interpreter reports no G20/G21 at all (canterp).
if (stat->activeGCodes[5] == G_20)
stat->programUnits = CANON_UNITS_INCHES;
else if (stat->activeGCodes[5] == G_21)
stat->programUnits = CANON_UNITS_MM;

//update state of optional stop
stat->optional_stop_state = GET_OPTIONAL_PROGRAM_STOP();

Expand Down
1 change: 1 addition & 0 deletions tests/program-units/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sim.var*
4 changes: 4 additions & 0 deletions tests/program-units/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Issue #3627: linuxcnc.stat.program_units followed the interpreter's
read-ahead, so it reported a G20 while a G21 move was still executing, and
disagreed with gcodes. This runs a 5 s G21 move followed by G20 and checks,
while the move executes, that program_units says mm whenever gcodes says G21.
2 changes: 2 additions & 0 deletions tests/program-units/checkresult
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
exit 0 # test failure is indicated by test.sh exit value
61 changes: 61 additions & 0 deletions tests/program-units/core_sim.hal
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# core HAL config file for simulation

# first load all the RT modules that will be needed
# kinematics
loadrt [KINS]KINEMATICS
#autoconverted 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=[KINS]JOINTS
# 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 joint.0.motor-pos-cmd => joint.0.motor-pos-fb ddt.0.in
net Ypos joint.1.motor-pos-cmd => joint.1.motor-pos-fb ddt.2.in
net Zpos joint.2.motor-pos-cmd => joint.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

63 changes: 63 additions & 0 deletions tests/program-units/test-ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env python3

import linuxcnc
import linuxcnc_util
import time
import sys


l = linuxcnc_util.LinuxCNC()
c, s = l.command, l.status
l.wait_for_linuxcnc_startup()

c.state(linuxcnc.STATE_ESTOP_RESET)
c.state(linuxcnc.STATE_ON)
c.home(-1)
c.wait_complete()
c.mode(linuxcnc.MODE_AUTO)
c.wait_complete()
c.program_open('test.ngc')
c.wait_complete()
s.poll()
if s.task_mode != linuxcnc.MODE_AUTO or not s.file.endswith('test.ngc'):
print('FAIL: not in AUTO with test.ngc open (mode %d, file %r)' % (s.task_mode, s.file))
sys.exit(1)
e = linuxcnc.error_channel()
c.auto(linuxcnc.AUTO_RUN, 0)

# While the G21 move executes, gcodes[5] (from the executing move) says G21.
# program_units must agree: before the fix it already showed the G20 that the
# interpreter had read ahead.
in_g21 = mismatch = 0
start = time.time()
while time.time() - start < 30:
s.poll()
if s.interp_state == linuxcnc.INTERP_IDLE and time.time() - start > 1:
break
if s.gcodes[5] == 210 and s.interp_state != linuxcnc.INTERP_IDLE:
in_g21 += 1
if s.program_units != 2: # CANON_UNITS_MM (no Python constant for it)
mismatch += 1
time.sleep(0.005)

s.poll()
while True:
msg = e.poll()
if not msg:
break
print('error channel: %s' % (msg[1],))
if s.interp_state != linuxcnc.INTERP_IDLE:
print('FAIL: the program did not finish within 30 s')
sys.exit(1)
print('samples while G21 executed: %d, program_units not mm in them: %d, end gcodes[5]=%d program_units=%d'
% (in_g21, mismatch, s.gcodes[5], s.program_units))
if in_g21 < 100:
print('FAIL: the G21 move was not seen executing')
sys.exit(1)
if mismatch:
print('FAIL: program_units disagreed with gcodes while the G21 move executed')
sys.exit(1)
if (s.gcodes[5], s.program_units) != (200, 1):
print('FAIL: after the program, G20 should be active in both')
sys.exit(1)
sys.exit(0)
117 changes: 117 additions & 0 deletions tests/program-units/test.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Simulated machine for tests/program-units (issue #3627), based on tests/abort/feed-rate.

[EMC]
# The version string for this INI file.
VERSION = 1.1

DEBUG = 0
RCS_DEBUG = 0x05400f01

[DISPLAY]
DISPLAY = ./test-ui.py

[FILTER]
#No Content

[RS274NGC]
PARAMETER_FILE = sim.var

[EMCMOT]
EMCMOT = motmod
COMM_TIMEOUT = 4.0
BASE_PERIOD = 0
SERVO_PERIOD = 1000000

[TASK]
TASK = milltask
CYCLE_TIME = 0.001

[HAL]
HALUI = halui
HALFILE = core_sim.hal

[HALUI]
#No Content
[TRAJ]

NO_FORCE_HOMING=1
AXES = 3
COORDINATES = X Y Z
HOME = 0 0 0
LINEAR_UNITS = inch
ANGULAR_UNITS = degree
DEFAULT_LINEAR_VELOCITY = 1.2
MAX_LINEAR_ACCELERATION = 123.45
MAX_LINEAR_VELOCITY = 45.67

[EMCIO]
TOOL_TABLE = simpockets.tbl
TOOL_CHANGE_QUILL_UP = 1
RANDOM_TOOLCHANGER = 0



[KINS]
KINEMATICS = trivkins
#This is a best-guess at the number of joints, it should be checked
JOINTS = 3

[AXIS_X]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0

[JOINT_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_Y]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0

[JOINT_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_Z]
MIN_LIMIT = -40.0
MAX_LIMIT = 40.0
MAX_VELOCITY = 4
MAX_ACCELERATION = 1000.0

[JOINT_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
5 changes: 5 additions & 0 deletions tests/program-units/test.ngc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
G21 (this move runs in mm)
G1 X25 F300 (about 5 s: the interpreter reads past it to the G20 long before it ends)
G20
G1 X0 F20
M2
5 changes: 5 additions & 0 deletions tests/program-units/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

rm -f sim.var
linuxcnc -r test.ini

Loading